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
}
CodePudding user response:
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.
