【发布时间】:2015-08-25 00:48:49
【问题描述】:
我只需要一个指向 time.Time 的指针,所以下面的代码似乎无效:
./c.go:5: 不能取time.Now()的地址
我只是想知道为什么?除了先对变量赋值并获取变量的指针之外,还有什么方法可以做到这一点?
package main
import "time"
func main() {
_ = &time.Now()
}
【问题讨论】:
我只需要一个指向 time.Time 的指针,所以下面的代码似乎无效:
./c.go:5: 不能取time.Now()的地址
我只是想知道为什么?除了先对变量赋值并获取变量的指针之外,还有什么方法可以做到这一点?
package main
import "time"
func main() {
_ = &time.Now()
}
【问题讨论】:
可能不令人满意的答案是“你不能这样做,因为规范是这样说的。”规范说,要在某些东西上使用&,它必须是addressable 或复合文字,并且要可寻址,它必须是“变量、指针间接或切片索引操作;或可寻址的字段选择器结构操作数;或可寻址数组的数组索引操作。”函数调用和方法调用肯定不在列表中。
实际上,这可能是因为函数的返回值可能没有一个可用的地址;它可能在一个寄存器中(在这种情况下它肯定是不可寻址的)或在堆栈上(在这种情况下它有一个地址,但如果它放在一个超出当前范围的指针中,则该地址将无效。为了保证可寻址性, Go 必须做几乎完全等同于将其分配给变量的操作. 但是 Go 是一种语言, 如果它要为变量分配存储空间, 那将是因为你说的, 而不是因为编译器神奇地决定这样做。所以它不会使函数的结果可寻址。
或者我可能想多了,他们根本不希望返回 一个 值的函数与返回多个值的函数有特殊情况:)
【讨论】:
你不能像 hobbs 所说的那样直接获取函数调用的地址(或者更准确地说是函数的返回值)。
还有另一种方法,但是很丑:
p := &[]time.Time{time.Now()}[0]
fmt.Printf("%T %p\n%v", p, p, *p)
输出(Go Playground):
*time.Time 0x10438180
2009-11-10 23:00:00 +0000 UTC
这里发生的是一个struct 是用一个文字创建的,包含一个元素(time.Now() 的返回值),切片被索引(第 0th 元素)和地址0th 元素被采用。
所以宁愿只使用一个局部变量:
t := time.Now()
p := &t
或辅助函数:
func ptr(t time.Time) *time.Time {
return &t
}
p := ptr(time.Now())
也可以是单行匿名函数:
p := func() *time.Time { t := time.Now(); return &t }()
或者作为替代:
p := func(t time.Time) *time.Time { return &t }(time.Now())
更多替代方案,请参见:
How do I do a literal *int64 in Go?
另见相关问题:How can I store reference to the result of an operation in Go?
【讨论】:
如果您在编写函数时遇到此问题,请将函数更改为返回指针。即使您不能获取返回值的地址,您也可以取消引用返回值,因此无论您想要指针还是对象都是合适的。
func Add(x, y int) *int {
tmp := x + y
return &tmp
}
func main() {
fmt.Println("I want the pointer: ", Add(3, 4))
fmt.Println("I want the object: ", *Add(3, 4))
}
【讨论】: