Do methods carry over with type B A vs type B = A vs embedding? What does this mean for sync.Mutex?
Question 105MediumGo 1.22 to 1.25
These are three different mechanisms:
- Defined type
type B A:Bhas the same underlying type asAbut none of A's declared methods. (IfAis an interface type,Bhas the same method set, because the methods are part of the interface's underlying type.) - Alias
type B = A:Bis just another name for the same type. It has all the methods and is fully interchangeable withA. - Embedding
type B struct{ A }:Bis a new type that promotes A's methods.
type MyMutex sync.Mutex
var m MyMutex
// m.Lock() // error: m.Lock undefined (type MyMutex has no field or method Lock)
(*sync.Mutex)(&m).Lock() // works via conversion (same underlying type)
type AliasMutex = sync.Mutex
var a AliasMutex
a.Lock() // OK: identical type
type Guarded struct {
sync.Mutex // promotes Lock/Unlock (on *Guarded)
data map[string]int
}
var g Guarded
g.Lock(); g.data = map[string]int{}; g.Unlock()
Dropping methods is a feature. It is how you break infinite recursion in custom MarshalJSON implementations:
func (u User) MarshalJSON() ([]byte, error) {
type plain User // no MarshalJSON method -> no recursion
return json.Marshal(struct {
plain
Kind string `json:"kind"`
}{plain(u), "user"})
}
Caveat: embedding sync.Mutex in an exported struct also exports Lock and Unlock as part of your API. Prefer an unexported field such as mu sync.Mutex.
More on Interfaces, Methods & Embedding
- Q103How does the "optional interface" (interface upgrade) pattern work? Give a stdlib example and its pitfall.
- Q104How do constraint interfaces in generics differ from ordinary interfaces?
- Q106How does
http.HandlerFuncwork? Explain the function-type adapter pattern. - Q107What happens when you call a value-receiver method through an interface that holds a nil pointer?
- Q108Can you modify a struct stored inside an interface? What does this print?
- Q109How do you write a generic function that needs to call a pointer-receiver method on
T? (thePT interface{ *T; M() }pattern)