我们编写了一个程序,通过它我们试图找到一个常量的地址。有可能这样做吗?
package main
func main() {
const k = 5
address := &k
}
它给出了一个错误,任何人都可以告诉我们如何找到常量的地址?
简而言之:你做不到。
错误消息说:
不能取k的地址
地址运算符&
的操作数有限制。 Spec: Address operators:
对于
x
类型的操作数T
,地址操作&x
生成*T
类型的指针到x
。操作数必须是可寻址的,即,变量,指针间接或切片索引操作;或可寻址结构操作数的字段选择器;或者可寻址数组的数组索引操作。作为可寻址性要求的一个例外,x
也可能是(可能是带括号的)composite literal。如果对x
的评估会导致run-time panic,那么对&x
的评估也是如此。
常量未列为可寻址,并且未在规范中列为可寻址(上面引用)的内容不能是地址运算符&
的操作数(不能取其地址)。
不允许采用常量的地址。这有两个原因:
如果需要一个指向值等于该常量的指针,请将其指定给一个可寻址的变量,这样就可以获取其地址,例如:
func main() {
const k = 5
v := k
address := &v // This is allowed
}
但是要知道Go中的数字常量表示任意精度的值而不会溢出。当您将常量的值赋给变量时,可能无法实现(例如,常量可能大于您为其分配的变量类型的最大值 - 导致编译时错误),或者它可能不相同(例如,在浮点常数的情况下,它可能会失去精度)。
在单元测试期间创建大型嵌套JSON对象时,我经常遇到此问题。我可能有一个结构,其中所有字段都是指向字符串/整数的指针:
type Obj struct {
Prop1 *string
Prop2 *int
Status *string
}
并想写一些类似的东西:
obj := Obj{
Prop1: &"a string property",
Prop2: &5,
Status: &statuses.Awesome,
}
当我初始化它时,但语言不允许直接使用它。绕过这个的一种快速方法是定义一个取常量并返回其地址的函数:
s := func(s string) *string { return &s }
i := func(s int) *int { return &i }
obj := Obj{
Prop1: s("a string property"),
Prop2: i(5),
Status: s(statuses.Awesome)
}
这是因为当常量作为参数传递给函数时,会产生一个常量的副本,这意味着在函数中创建的指针不指向常量的地址,而是指向其的地址。复制,与将常量值分配给var
的方式相同。但是,使用函数执行此操作会使IMO比转发声明大块变量更易读/更麻烦。
constants部分没有说清楚:与变量不同,常量不存在于编译代码或运行程序中。它们是无类型的,只有在分配给变量后才会在内存中。
结果,他们似乎具有无限的精确度。如果你看一下this example,你可以看到我可以将常量赋值给一个变量,而不需要强制转换它,变量将保持尽可能多的常量精度。
1正如spec也指出的那样,整数至少有256位,浮点数至少为256位尾数和32位指数,如果内部结构无法准确存储常量,编译器将抛出错误。