
Go 语言不允许对函数调用表达式(如 foo())使用取地址操作符 &,因为返回值不是可寻址对象;若需指针语义,应修改函数签名直接返回指针。
go 语言不允许对函数返回值直接取地址:原因与替代方案
在 Go 中,你可能会遇到类似这样的需求:有一个返回基本类型和错误的函数(如 `func foo() (int64, error)`),希望将第一个返回值直接取地址并赋给一个指针变量(例如 `var A *int64`),以避免复制大对象。但如下写法是**非法且编译不通过**的:A, err = &foo() // ❌ 编译错误:cannot take the address of foo()
这是因为 Go 的取地址操作符 & 要求其操作数必须是可寻址的(addressable)——即必须是一个变量、结构体字段、切片元素、数组元素,或复合字面量。而函数调用(如 foo())产生的返回值是一个临时值(r-value),不具备内存地址,因此不能对其取地址。
✅ 正确做法是:让函数本身返回指针,而非值。这既符合 Go 的内存模型,又避免了不必要的拷贝(尤其对大型结构体而言):
func foo() (*int64, error) {
val := int64(42)
return &val, nil
}
var A *int64
var err error
A, err = foo() // ✅ 合法:直接接收已分配好的指针⚠️ 注意事项:
- 若 foo() 内部返回局部变量的地址(如上例中的 &val),Go 编译器会自动进行逃逸分析(escape analysis),将 val 分配到堆上,确保指针有效;无需手动管理内存。
- 不要试图通过中间变量“绕过”限制(如 tmp := foo(); A = &tmp),这反而会引入一次冗余拷贝,违背初衷。
- 对于大型结构体,返回 *MyStruct 比 (MyStruct, error) 更高效且语义清晰;同时建议在文档中明确说明该指针是否可为 nil,以提升 API 可用性。
总结:Go 的设计哲学强调显式与安全——不可寻址的值不能取地址,这是防止悬空指针的关键保障。与其尝试语法捷径,不如重构接口,让函数契约天然支持指针语义。


















