
在 Go 中,无法直接对函数返回值取地址(如 &time.Now()),必须先将返回值赋给一个可寻址的局部变量,再对其取地址;虽然涉及一次复制,但这是语言规范要求的必要步骤,且开销极小。
在 go 中,无法直接对函数返回值取地址(如 `&time.now()`),必须先将返回值赋给一个可寻址的局部变量,再对其取地址;虽然涉及一次复制,但这是语言规范要求的必要步骤,且开销极小。
Go 的地址操作符 & 只能作用于可寻址(addressable) 的值,例如变量、结构体字段、切片元素等。而函数调用表达式(如 time.Now())本身是一个临时值(temporary value),不具有内存地址,因此 &time.Now() 在编译期就会报错:
cannot take the address of time.Now()
同理,f.t = time.Now() 也会失败,因为类型不匹配:time.Now() 返回 time.Time 类型,而 f.t 是 *time.Time 类型,Go 不允许隐式转换。
✅ 正确做法是引入一个局部变量(如 tmp),它在栈上分配、可寻址,从而支持取地址:
tmp := time.Now() // tmp 是可寻址的变量 f.t = &tmp // &tmp 合法:获取该变量的地址
这个过程确实包含一次值复制(time.Time 是 24 字节的结构体),但该复制是不可避免且高效的——它仅发生在栈上,无堆分配、无逃逸分析开销,也不构成“额外”成本。Go 编译器对此类模式高度优化,无需担忧性能影响。
⚠️ 注意事项:
- 不要尝试通过
new(time.Time)+*result = time.Now()等方式绕过,这反而增加冗余代码且语义不清; - 若业务逻辑中频繁需要
*time.Time,应评估是否真需区分“未设置”与“零值时间”。time.Time的零值(0001-01-01 00:00:00 +0000 UTC)虽古老,但常被用作“空时间”的标志,配合t.IsZero()判断即可; - 在数据库交互(如 SQL
NULL时间字段)或 API 可选字段场景下,*time.Time才真正必要——此时 nil 指针明确表示“无值”,优于依赖零值语义。
总结:局部变量不是权宜之计,而是 Go 内存模型和地址安全机制的设计必然;接受它、理解它,并善用 IsZero() 等方法简化逻辑,比强行规避更符合 Go 的惯用风格。











