方法

未匹配的标注

指针 vs. 值

正如 ByteSize 那样,我们可以为任何已命名的类型(除了指针或接口)定义方法; 接收者可不必为结构体。

在之前讨论切片时,我们编写了一个 Append 函数。 我们也可将其定义为切片的方法。为此,我们首先要声明一个已命名的类型来绑定该方法, 然后使该方法的接收者成为该类型的值。

type ByteSlice []byte

func (slice ByteSlice) Append(data []byte) []byte {
    // 主体与上面定义的Append函数完全相同。
}

我们仍然需要该方法返回更新后的切片。为了消除这种不便,我们可通过重新定义该方法, 将一个指向 ByteSlice 的指针作为该方法的接收者, 这样该方法就能重写调用者提供的切片了。

func (p *ByteSlice) Append(data []byte) {
    slice := *p
    // 主体同上,只是没有返回值
    *p = slice
}

其实我们做得更好。若我们将函数修改为与标准 Write 类似的方法,就像这样,

func (p *ByteSlice) Write(data []byte) (n int, err error) {
    slice := *p
    // 同上。
    *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。以指针或值为接收者的区别在于:值方法可通过指针和值调用, 而指针方法只能通过指针来调用。

之所以会有这条规则是因为指针方法可以修改接收者;通过值调用它们会导致方法接收到该值的副本, 因此任何修改都将被丢弃,因此该语言不允许这种错误。不过有个方便的例外:若该值是可寻址的, 那么该语言就会自动插入取址操作符来对付一般的通过值调用的指针方法。在我们的例子中,变量 b 是可寻址的,因此我们只需通过 b.Write 来调用它的 Write 方法,编译器会将它重写为 (&b).Write

顺便一提,在字节切片上使用 Write 的想法已被 bytes.Buffer 所实现。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/effective-go/20...

译文地址:https://learnku.com/docs/effective-go/20...

上一篇 下一篇
贡献者:3
讨论数量: 0
发起讨论 只看当前版本


暂无话题~