5.10. 方法

5.10.1. 指针vs值

方法可用于任意带名的非指针和界面的类型;接受者没必要是结构。

在上面讨论切片时,我们写了个 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 os.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 实现。