嵌入式类型(例如 mutex)应位于结构体内的字段列表的顶部,并且必须有一个空行将嵌入式字段与常规字段分隔开。

BadGood
type Client struct {
  version int
  http.Client
}
type Client struct {
  http.Client

  version int
}

内嵌应该提供切实的好处,比如以语义上合适的方式添加或增强功能。
它应该在对用户不利影响的情况下完成这项工作(另请参见:避免在公共结构中嵌入类型Avoid Embedding Types in Public Structs)。

嵌入 不应该:

  • 纯粹是为了美观或方便。
  • 使外部类型更难构造或使用。
  • 影响外部类型的零值。如果外部类型有一个有用的零值,则在嵌入内部类型之后应该仍然有一个有用的零值。
  • 作为嵌入内部类型的副作用,从外部类型公开不相关的函数或字段。
  • 公开未导出的类型。
  • 影响外部类型的复制形式。
  • 更改外部类型的API或类型语义。
  • 嵌入内部类型的非规范形式。
  • 公开外部类型的实现详细信息。
  • 允许用户观察或控制类型内部。
  • 通过包装的方式改变内部函数的一般行为,这种包装方式会给用户带来一些意料之外情况。

简单地说,有意识地和有目的地嵌入。一种很好的测试体验是,
“是否所有这些导出的内部方法/字段都将直接添加到外部类型”
如果答案是someno,不要嵌入内部类型-而是使用字段。

BadGood
type A struct {
    // Bad: A.Lock() and A.Unlock() 现在可用
    // 不提供任何功能性好处,并允许用户控制有关A的内部细节。
    sync.Mutex
}
type countingWriteCloser struct {
    // Good: Write() 在外层提供用于特定目的,
    // 并且委托工作到内部类型的Write()中。
    io.WriteCloser
    count int
}
func (w *countingWriteCloser) Write(bs []byte) (int, error) {
    w.count += len(bs)
    return w.WriteCloser.Write(bs)
}
type Book struct {
    // Bad: 指针更改零值的有用性
    io.ReadWriter
    // other fields
}
// later
var b Book
b.Read(...)  // panic: nil pointer
b.String()   // panic: nil pointer
b.Write(...) // panic: nil pointer
type Book struct {
    // Good: 有用的零值
    bytes.Buffer
    // other fields
}
// later
var b Book
b.Read(...)  // ok
b.String()   // ok
b.Write(...) // ok
type Client struct {
    sync.Mutex
    sync.WaitGroup
    bytes.Buffer
    url.URL
}
type Client struct {
    mtx sync.Mutex
    wg  sync.WaitGroup
    buf bytes.Buffer
    url url.URL
}
最后编辑: kuteng  文档更新时间: 2021-05-09 20:12   作者:kuteng