

Go 挖坑指南: “cannot take the address of XXX” and “cannot call pointer method on...
source link: https://shockerli.net/post/golang-faq-cannot-take-the-address/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

先看代码
package main type B struct { Id int } func New() B { return B{} } func New2() *B { return &B{} } func (b *B) Hello() { return } func (b B) World() { return } func main() { // 方法的接收器为 *T 类型 New().Hello() // 编译不通过 b1 := New() b1.Hello() // 编译通过 b2 := B{} b2.Hello() // 编译通过 (B{}).Hello() // 编译不通过 B{}.Hello() // 编译不通过 New2().Hello() // 编译通过 b3 := New2() b3.Hello() // 编译通过 b4 := &B{} // 编译通过 b4.Hello() // 编译通过 (&B{}).Hello() // 编译通过 // 方法的接收器为 T 类型 New().World() // 编译通过 b5 := New() b5.World() // 编译通过 b6 := B{} b6.World() // 编译通过 (B{}).World() // 编译通过 B{}.World() // 编译通过 New2().World() // 编译通过 b7 := New2() b7.World() // 编译通过 b8 := &B{} // 编译通过 b8.World() // 编译通过 (&B{}).World() // 编译通过 }
输出结果
./main.go:25:10: cannot call pointer method on New() ./main.go:25:10: cannot take the address of New() ./main.go:33:10: cannot call pointer method on B literal ./main.go:33:10: cannot take the address of B literal ./main.go:34:8: cannot call pointer method on B literal ./main.go:34:8: cannot take the address of B literal
问题总结
假设 T
类型的方法上接收器既有 T
类型的,又有 *T
指针类型的,那么就不可以在不能寻址的 T
值上调用 *T
接收器的方法
&B{} B{} b := B{}
延伸思考
Go 语言规范 中规定了可寻址(addressable)对象的定义:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal. If the evaluation of x would cause a run-time panic, then the evaluation of &x does too.
对于类型为 T
的操作数 x
,地址操作符 &x
将生成一个类型为 *T
的指针指向 x
。操作数必须可寻址,即,变量、间接指针、切片索引操作,或可寻址结构体的字段选择器,或可寻址数组的数组索引操作。作为可寻址性要求的例外, x
也可为(圆括号括起来的)复合字面量。如果对 x
的求值会引起运行时恐慌,那么对 &x
的求值也会引起恐慌。
For an operand x of pointer type *T, the pointer indirection *x denotes the variable of type T pointed to by x. If x is nil, an attempt to evaluate *x will cause a run-time panic.
对于指针类型为 *T
的操作数 x
,间接指针 *x
表示类型为 T
的值指向 x
。若 x
为 nil
,尝试求值 *x
将会引发运行时恐慌。
以下几种是可寻址的:
&x &*x &s[1] &point.X &a[0] &struct{ X int }{1}
下列情况 x
是不可以寻址的,不能使用 &x
取得指针:
- 字符串中的字节
- map 对象中的元素
- 接口对象的动态值(通过 type assertions 获得)
- 常数
- literal 值(非 composite literal)
- package 级别的函数
- 方法 method(用作函数值)
-
中间值(intermediate value):
- 函数调用
- 显式类型转换
-
各种类型的操作(除了指针引用 pointer dereference 操作
*x
):- channel receive operations
- sub-string operations
- sub-slice operations
- 加减乘除等运算符
有几个点需要解释下:
-
常数为什么不可以寻址? > 如果可以寻址的话,我们可以通过指针修改常数的值,破坏了常数的定义。
-
map 的元素为什么不可以寻址? > 两个原因,如果对象不存在,则返回零值,零值是不可变对象,所以不能寻址,如果对象存在,因为 Go 中 map 实现中元素的地址是变化的,这意味着寻址的结果是无意义的。
-
为什么 slice 不管是否可寻址,它的元素读是可以寻址的? > 因为 slice 底层实现了一个数组,它是可以寻址的。
-
为什么字符串中的字符/字节又不能寻址呢? > 因为字符串是不可变的。
规范中还有几处提到了 addressable:
- 调用一个接收者为指针类型的方法时,使用一个可寻址的值将自动获取这个值的指针
-
++
、--
语句的操作对象必须可寻址或者是 map 的索引操作 -
赋值语句
=
的左边对象必须可寻址,或者是 map 的索引操作,或者是_
-
上条同样使用
for ... range
语句
参考资料
Recommend
-
90
亲历的手机扣费乱象,连续遭遇的三大“坑”,并不是“别人家的故事”。很多人都曾有亲身遭遇,也曾进行投诉,也都碰到了“态度很好,然而无用”。这也提醒有关方面,在维护市场秩序时,必须把重点放在投诉机制的建立与作用发挥上。旧号码莫名其妙被“低消”近
-
52
Oracle 12c dataguard云上挖坑记--为某机场贵宾业务部署oracle 12c到百度云项目需求据称现有环境为多节点RAC,管理成本高,主要体现在没有专业技术人家对基础设施进行维护。迁移到云上以后,基础设施维护就节省掉了。而且后边容量扩充易如反掌,远程维护之类也比物...
-
44
居然有这样挖坑的,被全国知名大券商坑了,如何维权要回损失?附事件详细情况。 - 情况是这样的:2016年4月A券商(国内排名前5的大券商)客服经理B(正式员工)向我推销他们公司的集合资产管理计划产品C,说这个产品C全部投资世界知名CTA公司元盛公司的期货管理CTA...
-
53
小程序出来那么久一直没有深入的开发,这次借着公司要做小程序,深入探索了一番,结果挖坑无数,当然,仅限挖坑,并没有填完。哈哈,就先mark一下。 因为公司业务需求,这次小程序用的是 mpvue + typescript 进行开发。 mpvue 相关的坑 关于in
-
27
在这个系列中,我们尝试从能量的视角理解 GAN。我们会发现这个视角如此美妙和直观,甚至让人拍案叫绝。 本视角直接受启发于 Bengio 团队的新作 Maximum Entropy Generators for Energy-Based Models [...
-
34
比特币挖坑,电费挖阱:青海淘金的魔幻现实主义故事 ...
-
36
Invalid memory address or nil pointer dereference yourbasic.org/golang Why does this program panic? typ...
-
9
Why am I getting a null pointer crash when trying to call a method on my C++/WinRT object?
-
7
On the overloading of the address-of operator & in smart pointer classes
-
7
panic: runtime error: invalid memory address or nil pointer dereference | 关于nil 无效的指针引用的问题
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK