即使所有方法都是用值接收器定义的,也改变结构的切片字段

Mutating a slice field of a struct even though all methods are defined with value receivers

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)

我理解引用的一般含义,但我想知道复制该类型的实例是安全的说法是否正确。

如果一个结构有一个 slice/map 字段,那么所有副本都会收到它们自己的指向支持的指针的副本 array/hashmap 因此仍然可以改变这些数据结构。

即使所有方法都可以使用值接收器定义,我们也可以打破结构的内部状态。

我明白为什么会这样,但这种可能性是否与上面那段内容相矛盾?

无论方法接收者如何,复制值都可能会产生不良后果,并且还取决于字段类型。

我在这里错过了什么?

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
}

我既不是 Donovan 也不是 Kernighan,所以我不能明确地说出他们试图在这里交流的内容,但我的理解不是“使用价值接收者 使 复制安全”,而是“使用值接收者 表示 复制是安全的”。您是正确的,任何指针字段或包含指针字段(包括切片和映射)的任何字段都会使复制不安全;我相信作者试图表达的意思是,使用值接收器的 API 向其消费者表明不存在此类字段。