## 指針 vs. 值
正如我們從`ByteSize`上看到的,任何命名類型(指針和接口除外)都可以定義方法(method);接收者(receiver)不必為一個結構體。
在上面有關切片的討論中,我們編寫了一個`Append`函數。我們還可以將其定義成切片的方法。為此,我們首先聲明一個用于綁定該方法的命名類型,然后將方法的接收者作為該類型的值。
~~~
type ByteSlice []byte
func (slice ByteSlice) Append(data []byte) []byte {
// Body exactly the same as above
}
~~~
這樣還是需要方法返回更新后的切片。我們可以通過重新定義方法,接受一個`ByteSlice`的*指針*作為它的接收者,來消除這樣笨拙的方式。這樣,方法就可以改寫調用者的切片。
~~~
func (p *ByteSlice) Append(data []byte) {
slice := *p
// Body as above, without the return.
*p = slice
}
~~~
實際上,我們可以做的更好。如果我們將函數修改成標準`Write`方法的樣子,像這樣,
~~~
func (p *ByteSlice) Write(data []byte) (n int, err error) {
slice := *p
// Again as above.
*p = slice
return len(data), nil
}
~~~
那么類型`*ByteSlice`就會滿足標準接口`io.Writer`,這樣就很方便。例如,我們可以打印到該類型的變量中。
~~~
var b ByteSlice
fmt.Fprintf(&b, "This hour has %d days\n", 7)
~~~
我們傳遞`ByteSlice`的地址,是因為只有`*ByteSlice`才滿足`io.Writer`。關于接收者對指針和值的規則是這樣的,值方法可以在指針和值上進行調用,而指針方法只能在指針上調用。這是因為指針方法可以修改接收者;使用拷貝的值來調用它們,將會導致那些修改會被丟棄。
順便說一下,在字節切片上使用`Write`的思想,是實現`bytes.Buffer`的核心。