为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在值而不是指针上定义方法?

为什么在值而不是指针上定义方法?

Go
心有法竹 2021-07-30 17:55:25
查看示例 Go 代码,有些事情是不一致的。许多代码在指针类型上定义了它们的方法,例如:func (p *parser) parse () {...}但是其他一些代码只定义类型的方法,而不是指向它的指针:func (s scanner) scan () {...}有充分的理由做后者吗?通过值而不是指针传递对象真的能更有效吗?一个原因是“我无法更改此对象”,但这无论如何都是大对象的问题(您是否会按值传递 big struct 只是为了标记它不能通过方法更改?)
查看完整描述

2 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

幸运的是,这是在Go FAQ 中

我应该定义值还是指针的方法?

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value`

对于不习惯指针的程序员来说,这两个例子之间的区别可能会令人困惑,但情况其实很简单。在类型上定义方法时,接收器(在上面的示例中为 s)的行为就像它是方法的参数一样。将接收者定义为值还是指针是同一个问题,然后,函数参数应该是值还是指针。有几个考虑。

首先,也是最重要的,该方法是否需要修改接收器?如果是,则接收者必须是一个指针。(切片和映射充当引用,所以它们的故事有点微妙,但例如要更改方法中切片的长度,接收者仍然必须是指针。)在上面的示例中,如果 pointerMethod 修改了s,调用者将看到这些更改,但 valueMethod 是使用调用者参数的副本(这是传递值的定义)调用的,因此调用者将看不到它所做的更改。

顺便说一下,指针接收器与 Java 中的情况相同,尽管在 Java 中指针隐藏在幕后;Go 的价值接收者是不寻常的。

二是对效率的考虑。如果接收器很大,例如一个大的结构,使用指针接收器会便宜得多。

接下来是一致性。如果该类型的某些方法必须有指针接收器,其余的也应该如此,因此无论如何使用该类型,方法集都是一致的。有关详细信息,请参阅方法集部分。

对于诸如基本类型、切片和小型结构之类的类型,值接收器非常便宜,因此除非方法的语义需要指针,否则值接收器是高效且清晰的。

所以是的,它主要用于语义。在处理并发时,知道一个方法没有副作用是一件好事,因为这自动意味着不需要锁定。除了全局变量和引用类型,值接收器强烈暗示您的方法没有副作用。


查看完整回答
反对 回复 2021-08-02
?
蓝山帝景

TA贡献1843条经验 获得超7个赞

方法链也是一个考虑因素。如果你想能够写

one.Two().Three()

然后要么Two()需要返回一个指针,要么Three()需要有一个值接收器,因为方法调用的结果是不可寻址的。如果Two返回一个值,则无法获取其地址以对其调用指针接收器方法。但是,如果Three()有值接收器,则无论是否Two()返回指针都将起作用。


查看完整回答
反对 回复 2021-08-02
  • 2 回答
  • 0 关注
  • 235 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信