




Go函数天然支持多返回值,是语法层核心特性而非语法糖;标准库函数常以error为最后返回值,须显式接收避免panic;命名返回值提升可读性但需注意初始化;多返回值非元组,不可直接传入单参数函数。
Go 语言从语法层就允许函数声明多个返回值,这不是语法糖或库功能,而是核心特性。函数签名中用括号包裹多个类型即可,比如 func foo() (int, string)。调用时可全接收、可部分接收(用空白标识符 _ 忽略)、也可直接赋值给多个变量——没有隐式转换或包装成本,底层就是寄存器/栈上的并行传值。
Go 标准库和多数规范函数都把错误作为最后一个返回值,例如 os.Open() 返回 (*os.File, error)。新手常写成 f := os.Open("x.txt"),结果 f 是 *os.File 类型,但实际第一个值是文件句柄,第二个才是 error;漏判错误会导致后续操作 panic。
f, err := os.Open("x.txt")
_, err := strconv.Atoi("abc")
if os.Open("x.txt") != nil —— 这语法非法,os.Open 返回两个值,无法直接与 nil 比较在函数签名中给返回值起名(如 func bar() (result int, err error)),会让代码更易读,尤其配合 defer 使用时:命名返回值在函数入口就已声明,defer 中可直接引用并修改它们的值。
func parseConfig() (cfg Config, err error) {
f, err := os.Open("config.json")
if err != nil {
return // 此处 cfg 是零值,err 是上一步的 error
}
defer f.Close()
err = json.NewDecoder(f).Decode(&cfg)
return // 只需 return,cfg 和 err 都已就位
}
注意:命名返回值会略微增加栈开销,且容易掩盖未初始化的变量(比如忘了给 cfg 赋值),调试时需留意其实际值是否被中途修改过。
立即学习“go语言免费学习笔记(深入)”;
G

foo() 的结果直接塞进另一个函数,除非显式解包:
fmt.Println(foo()) —— foo() 返回两个值,fmt.Println 接收可变参数,但这里会报 “too many arguments”a, b := foo(); fmt.Println(a, b) 或 fmt.Println(foo()) 实际能工作,是因为 fmt.Println 是可变参数函数,会把多返回值展开为独立实参 —— 但这属于特例,不可泛化func takeOne(x int)),则 takeOne(foo()) 编译失败,必须先解包这种“非元组”设计避免了类型系统复杂化,但也意味着不能靠返回值自动适配接口,得靠人来拆解。