snapshot of https://github.com/uber-go/guide.git (master, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
156
src/struct-embed.md
Normal file
156
src/struct-embed.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Embedding in Structs
|
||||
|
||||
Embedded types should be at the top of the field list of a
|
||||
struct, and there must be an empty line separating embedded fields from regular
|
||||
fields.
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Bad</th><th>Good</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>
|
||||
|
||||
```go
|
||||
type Client struct {
|
||||
version int
|
||||
http.Client
|
||||
}
|
||||
```
|
||||
|
||||
</td><td>
|
||||
|
||||
```go
|
||||
type Client struct {
|
||||
http.Client
|
||||
|
||||
version int
|
||||
}
|
||||
```
|
||||
|
||||
</td></tr>
|
||||
</tbody></table>
|
||||
|
||||
Embedding should provide tangible benefit, like adding or augmenting
|
||||
functionality in a semantically-appropriate way. It should do this with zero
|
||||
adverse user-facing effects (see also: [Avoid Embedding Types in Public Structs](embed-public.md)).
|
||||
|
||||
Exception: Mutexes should not be embedded, even on unexported types. See also: [Zero-value Mutexes are Valid](mutex-zero-value.md).
|
||||
|
||||
Embedding **should not**:
|
||||
|
||||
- Be purely cosmetic or convenience-oriented.
|
||||
- Make outer types more difficult to construct or use.
|
||||
- Affect outer types' zero values. If the outer type has a useful zero value, it
|
||||
should still have a useful zero value after embedding the inner type.
|
||||
- Expose unrelated functions or fields from the outer type as a side-effect of
|
||||
embedding the inner type.
|
||||
- Expose unexported types.
|
||||
- Affect outer types' copy semantics.
|
||||
- Change the outer type's API or type semantics.
|
||||
- Embed a non-canonical form of the inner type.
|
||||
- Expose implementation details of the outer type.
|
||||
- Allow users to observe or control type internals.
|
||||
- Change the general behavior of inner functions through wrapping in a way that
|
||||
would reasonably surprise users.
|
||||
|
||||
Simply put, embed consciously and intentionally. A good litmus test is, "would
|
||||
all of these exported inner methods/fields be added directly to the outer type";
|
||||
if the answer is "some" or "no", don't embed the inner type - use a field
|
||||
instead.
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Bad</th><th>Good</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>
|
||||
|
||||
```go
|
||||
type A struct {
|
||||
// Bad: A.Lock() and A.Unlock() are
|
||||
// now available, provide no
|
||||
// functional benefit, and allow
|
||||
// users to control details about
|
||||
// the internals of A.
|
||||
sync.Mutex
|
||||
}
|
||||
```
|
||||
|
||||
</td><td>
|
||||
|
||||
```go
|
||||
type countingWriteCloser struct {
|
||||
// Good: Write() is provided at this
|
||||
// outer layer for a specific
|
||||
// purpose, and delegates work
|
||||
// to the inner type's Write().
|
||||
io.WriteCloser
|
||||
|
||||
count int
|
||||
}
|
||||
|
||||
func (w *countingWriteCloser) Write(bs []byte) (int, error) {
|
||||
w.count += len(bs)
|
||||
return w.WriteCloser.Write(bs)
|
||||
}
|
||||
```
|
||||
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
```go
|
||||
type Book struct {
|
||||
// Bad: pointer changes zero value usefulness
|
||||
io.ReadWriter
|
||||
|
||||
// other fields
|
||||
}
|
||||
|
||||
// later
|
||||
|
||||
var b Book
|
||||
b.Read(...) // panic: nil pointer
|
||||
b.String() // panic: nil pointer
|
||||
b.Write(...) // panic: nil pointer
|
||||
```
|
||||
|
||||
</td><td>
|
||||
|
||||
```go
|
||||
type Book struct {
|
||||
// Good: has useful zero value
|
||||
bytes.Buffer
|
||||
|
||||
// other fields
|
||||
}
|
||||
|
||||
// later
|
||||
|
||||
var b Book
|
||||
b.Read(...) // ok
|
||||
b.String() // ok
|
||||
b.Write(...) // ok
|
||||
```
|
||||
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
```go
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
sync.WaitGroup
|
||||
bytes.Buffer
|
||||
url.URL
|
||||
}
|
||||
```
|
||||
|
||||
</td><td>
|
||||
|
||||
```go
|
||||
type Client struct {
|
||||
mtx sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
buf bytes.Buffer
|
||||
url url.URL
|
||||
}
|
||||
```
|
||||
|
||||
</td></tr>
|
||||
</tbody></table>
|
||||
Reference in New Issue
Block a user