英文:
What is the difference between Pointer and Value receiver types?
问题
我正在写一个程序,它从io.Reader中读取数据并将其缓存在bytes.Buffer中。
type SecureReader struct {
pipe io.Reader
shared *[32]byte
decrypted bytes.Buffer
}
func (s SecureReader) Read(b []byte) (int, error) {
s.decryptPipeIntoBuffer()
return s.decrypted.Read(b)
}
func (s SecureReader) decryptPipeIntoBuffer() (int, error) {/*很多代码...*/}
起初,我使用了值接收器,因为我以为它们是一样的。然而,我注意到当调用SecureReader.Read()方法时,它什么也不做,总是返回io.EOF。
我苦思冥想并将接收器类型更改为:
func (s *SecureReader) decryptPipeIntoBuffer() (int, error) {/*很多代码...*/}
现在我的代码神奇地正常工作了。发生了什么?
英文:
I was writing a program that reads data from a io.Reader and caches them in a bytes.Buffer.
type SecureReader struct {
pipe io.Reader
shared *[32]byte
decrypted bytes.Buffer
}
func (s SecureReader) Read(b []byte) (int, error) {
s.decryptPipeIntoBuffer()
return s.decrypted.Read(b)
}
func (s SecureReader) decryptPipeIntoBuffer() (int, error) {/*Lots of code...*/}
I first used a value receiver, because I thought they were the same. However, I noticed my method does not do anything when invoked: SecureReader.Read() would always return io.EOF.
I banged my head around and changed the receiver type to
func (s *SecureReader) decryptPipeIntoBuffer() (int, error) {/*Lots of code...*/}
Now my code magically works. What is going on?
答案1
得分: 3
一个值接收器在 SecureReader
实例 s
的 副本 上操作。
如果该方法修改了实例的 副本 的任何部分(比如修改 s.decrypted
),一旦方法退出,这些修改对于原始实例是不可见的。
而使用指针接收器则不同,该方法在实际的 SecureReader
实例 s
上操作并可以修改它,因为指针的 副本 被传递给方法。
在“不要被Go中的指针和非指针方法接收器所困扰”中可以看到更多示例。
简单来说:你可以将接收器视为传递给方法的参数。所有你可能希望按值传递或按引用传递的原因都适用。
为什么要选择按引用传递而不是按值传递的原因:
- 你想要实际修改接收器(“读/写”而不仅仅是“读取”)
- 结构体非常大,深拷贝代价昂贵
- 一致性:如果结构体的某些方法具有指针接收器,其余方法也应该有。这样可以保证行为的可预测性。
如果你需要这些特性来调用方法,请使用指针接收器。
英文:
A value receiver operates on a copy of the SecureReader
instance s
.
If the method mutates any part of the copy of the instance (like modify s.decrypted
), it is not visible on the original instance of the receiver, once the method exit.
That changes with a pointer receiver, where the method operates and can mutates the actual SecureReader
instance s
, since a copy of the pointer is passed to the method.
See more examples in "Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang".
> Simply stated: you can treat the receiver as if it was an argument being passed to the method. All the same reasons why you might want to pass by value or pass by reference apply.
> Reasons why you would want to pass by reference as opposed to by value:
> - You want to actually modify the receiver (“read/write” as opposed to just “read”)
- The struct is very large and a deep copy is expensive
- Consistency: if some of the methods on the struct have pointer receivers, the rest should too. This allows predictability of behavior
> If you need these characteristics on your method call, use a pointer receiver.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论