使用匿名结构进行合成与继承

I was reading this slideshow, which says:

var hits struct {
    sync.Mutex
    n int
}

hits.Lock()
hits.n++
hits.Unlock()

How does that work exactly? Seems like hits isn't composed of a mutex and integer, but is a mutex and integer?

It's called embedding, hits is composed of a sync.Mutex and an int. This should be true since there is really no inheritance in Go. This is more of a "has a" rather than an "is a" relationship between the members and the struct.

Read here for a more complete explanation

Quoted from the link

The methods of embedded types come along for free

That means you can access them like hits.Lock() instead of the longer form hits.Mutex.Lock() because the function Lock() is not ambiguous.

See the Go-syntax representation of hits variable:

fmt.Printf("%#v
", &hits)
// &struct { sync.Mutex; n int }{Mutex:sync.Mutex{state:0, sema:0x0}, n:1}

When you declare the variable, it simply initializes the fields in struct with their default values.

Also, compiler automatically sets the name of the embedded struct as a field. So you can also access like:

hits.Mutex.Lock()
hits.Mutex.Unlock()

And you have access to all methods and exported fields (if any) of sync.Mutex.

It is composition. Using an anonymous field (embedded field), the containing struct will have a value of the embedded type, and you can refer to it: the unqualified type name acts as the field name.

So you could just as easily write:

hits.Mutex.Lock()
hits.n++
hits.Mutex.Unlock()

When you embed a type, fields and methods of the embedded type get promoted, so you can refer to them without specifying the field name (which is the embedded type name), but this is just syntactic sugar. Quoting from Spec: Selectors:

A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T.

Beyond the field / method promotion, the method set of the embedder type will also contain the method set of the embedded type. Quoting from Spec: Struct types:

Given a struct type S and a defined type T, promoted methods are included in the method set of the struct as follows:

  • If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.

  • If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

This is not inheritance in the OOP sense, but something similar. This comes handy when you want to implement an interface: if you embed a type that already implements the interface, so will your struct type. You can also provide your own implementation of some methods, which gives the feeling of method overriding, but must not be forgetten that selectors that denote methods of the embedded type will get the embedded value as the receiver (and not the embedder value), and selectors that denote your methods defined on the struct type (that may or may not "shadow" a method of the embedded type) will get the embedder struct value as the receiver.