英文:
Mutating a slice field of a struct even though all methods are defined with value receivers
问题
6.2 使用指针接收器的方法
如果一个命名类型 T 的所有方法都具有 T 本身作为接收器类型(而不是 *T),那么复制该类型的实例是安全的;调用其任何方法都会自动进行复制。例如,time.Duration 值会被大量复制,包括作为函数参数传递。但是,如果任何方法具有指针接收器,应避免复制 T 的实例,因为这样做可能会违反内部不变性。例如,复制 bytes.Buffer 的实例会导致原始实例和副本别名(§2.3.2)相同的底层数组。后续的方法调用将产生不可预测的效果。
(《Go 程序设计语言》Alan A. A. Donovan · Brian W. Kernighan)
我理解这段引文的大致意思,但我想知道是否可以说复制该类型的实例是安全的。
如果一个结构体具有切片/映射字段,那么所有的副本都会收到指向底层数组/哈希表的指针的副本,因此仍然有可能改变这些数据结构。
即使所有的方法都是使用值接收器定义的,我们仍然可以破坏结构体的内部状态。
我理解为什么会发生这种情况,但这种可能性是否与上述段落中所写的相矛盾?
复制值可能会产生意想不到的后果,无论方法接收器如何,并且还取决于字段类型。
我在这里漏掉了什么?
package main
import "fmt"
type T struct {
s []string
}
func main() {
original := T{s: []string{"original"}}
copycat := original
copycat.s[0] = "copycat"
fmt.Println(original.s[0] == "copycat") // true
}
英文:
> 6.2 Methods with a Pointer Receiver
>
> If all the methods of a named type T have a receiver type of T itself
> (not *T ), it is safe to copy instances of that type; calling any of
> its methods necessarily makes a copy. For example, time.Duration
> values are liberally copied, including as arguments to functions. But
> if any method has a pointer receiver, you should avoid copying
> instances of T because doing so may violate internal invariants. For
> example, copying an instance of bytes.Buffer would cause the original
> and the copy to alias ( §2.3.2 ) the same underlying array of bytes.
> Subsequent method calls would have unpredictable effects.
>
> (The Go Programming Language Alan A. A. Donovan · Brian W. Kernighan)
I understand the general meaning of the quote, but I am wondering whether it's correct to say that is safe to copy instances of that type.
If a struct has a slice/map field then all copies receive their own copies of the pointers to the backing array/hashmap so it is still possible to mutate those data structures.
Even though all the methods might be defined using value receivers, we can break the internal state of the struct.
I understand why that happens, but doesn't that possibility contradict what is written in that paragraph above?
Copying values might have unwanted consequences regardless of the method receivers and also depends on the field types.
What am I missing here?
package main
import "fmt"
type T struct {
s []string
}
func main() {
original := T{s: []string{"original"}}
copycat := original
copycat.s[0] = "copycat"
fmt.Println(original.s[0] == "copycat") // true
}
答案1
得分: 5
我不是Donovan或Kernighan,所以我不能确定他们在这里试图传达什么,但我的理解不是"使用值接收器使得复制安全",而是"使用值接收器表明复制是安全的"。你说得对,任何指针字段,或者包含指针字段的字段(包括切片和映射),都会使得复制不安全;我相信作者试图传达的是,使用值接收器的API向其使用者表明不存在这样的字段。
英文:
I'm neither Donovan nor Kernighan, so I can't definitively say what they were trying to communicate here, but my understanding is not that "using value receivers makes copying safe", but rather "using value receivers indicates copying is safe". You are correct that any pointer field, or any field which contains a pointer field (including slices and maps), will make copying unsafe; I believe what the authors are trying to get across is that an API which uses a value receiver is indicating to its consumers that no such fields exist.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论