关于golang:译-方法是否应该在-T-或-T-上声明

32次阅读

共计 1289 个字符,预计需要花费 4 分钟才能阅读完成。

情谊提醒:此篇文章大概须要浏览 3 分钟 49 秒,不足之处请多指教,感谢您的浏览。订阅本站

译文原地址:Should methods be declared on T or *T – David

在 Go 中,对于任何的类型 T,都存在一个类型 *T,他是一个表达式的后果,该表达式接管的是类型 T,例如:

type T struct {a int; b bool} 
var t T    // t's type is T 
var p = &t // p's type is *T

这两种类型,T 和 *T 是不同的,但 *T 不能代替 T。

你能够在你领有的任意类型上申明一个办法;也就是说,在您的包中的函数申明的类型。因而,您能够在申明的类型 T 和对应的派生指针类型 *T 上申明办法。另一种说法是,类型上的办法被申明为接收器接收者值的正本,或一个指向其接收者值的指针。所以问题就存在了,到底是哪种模式最合适?

显然,如果你的办法扭转了他的接收者,他应该在 *T 上申明。然而,如果办法不扭转他的接收者,在 T 上申明它是平安的么?

事实证明,这样做的话平安的状况十分无限(简略了解就是不平安的)。例如,家喻户晓,你不应该复制一个 sync.Mutex 的值,因为它突破了互斥量的不变量。因为互斥锁管制对变量(共享资源)的拜访,他们常常被包装在一个构造体中,蕴含他们的管制的值(共享资源):

package counter

type Val struct {
    mu  sync.Mutex
    val int
}

func (v *Val) Get() int {v.mu.Lock()
    defer v.mu.Unlock()
    return v.val
}

func (v *Val) Add(n int) {v.mu.Lock()
    defer v.mu.Unlock()
    v.val += n
}

大部分 Gopher 都晓得,遗记在指针接收器 *Val 上是申明 Get 或 Add 办法是谬误的。然而,任何嵌入 Val 来利用其 0 值的类型,也必须仅在其指针接收器上申明办法,否者可能会无心复制其嵌入类型值的内容:

type Stats struct {a, b, c counter.Val}

func (s Stats) Sum() int {return s.a.Get() + s.b.Get() + s.c.Get() // whoops(哎呀)}

保护值切片的类型可能会呈现相似的陷阱,当然也有可能发生意外的数据竞争。

简而言之,我认为您更应该喜爱在 *T 上申明办法,除非您有十分充沛的理由不该这样做。

  1. 咱们说 T 但这只是您申明的类型的占位符;
  2. 此规定是递归的,取 *T 类型的变量的地址返回的是 **T 类型的后果;
  3. 这就是为什么没有人能够在像 int 这样的根底类型上申明办法;
  4. Go 中的办法只是将接受者作为第一个模式参数传递的函数的语法糖;
  5. 如果办法不扭转它的接收者,它是否须要是一个办法吗?

相干文章:

  1. What is the zero value, and why is it useful?
  2. Ice cream makers and data races
  3. Slices from the ground up
  4. The empty struct

最初,此篇文章我是第一次尝试翻译英文文章,只管英文程度不太好,一些单词不意识,然而置信本人翻译一篇文章能够学习英语与了解 Go 设计获取 double 的乐趣。

正文完
 0