结构体中的嵌入
发布者:admin 发表于:451天前 阅读数:536 评论:0

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

Bad Good

type Client struct { version int http.Client } |

type Client struct { http.Client

version int } |

内嵌应该提供切实的好处,比如以语义上合适的方式添加或增强功能。

它应该在对用户不利影响的情况下完成这项工作(另请参见:避免在公共结构中嵌入类型Avoid Embedding Types in Public Structs)。

嵌入 不应该:

纯粹是为了美观或方便。

使外部类型更难构造或使用。

影响外部类型的零值。如果外部类型有一个有用的零值,则在嵌入内部类型之后应该仍然有一个有用的零值。

作为嵌入内部类型的副作用,从外部类型公开不相关的函数或字段。

公开未导出的类型。

影响外部类型的复制形式。

更改外部类型的API或类型语义。

嵌入内部类型的非规范形式。

公开外部类型的实现详细信息。

允许用户观察或控制类型内部。

通过包装的方式改变内部函数的一般行为,这种包装方式会给用户带来一些意料之外情况。

简单地说,有意识地和有目的地嵌入。一种很好的测试体验是,

“是否所有这些导出的内部方法/字段都将直接添加到外部类型”

如果答案是someno,不要嵌入内部类型-而是使用字段。

Bad Good

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 } |