Gold, an experimental Go local docs server, Go docs generation tool, and code reader. NEW!

-- show type implemention relations --

-- show code statistics --

-- smooth code view experiences --

-- and more... --

Type Embedding

From the article structs in Go, we know that a struct type can have many fields. Each field is composed of one field name and one field type. In fact, sometimes, a struct field can be composed of a field type only. The way to declare struct fields is called type embedding.

This article will explain the purpose of type embedding and all kinds of details in type embedding.

What Does Type Embedding Look Like?

package main import "net/http" func main() { type P = *bool type M = map[int]int var x struct { string // a defined non-pointer type error // a defined interface type *int // a non-defined pointer type P // an alias of a non-defined pointer type M // an alias of a non-defined type http.Header // a defined map type } x.string = "Go" x.error = nil x.int = new(int) x.P = new(bool) x.M = make(M) x.Header = http.Header{} } Here is an example demonstrating type embedding: In the above example, six types are embedded in the struct type. Each type embedding forms an embedded field. Embedded fields are also called as anonymous fields. However, each embedded field has a name specified implicitly. The unqualified type name of an embedded field acts as the name of the field. For example, the names of the six embedded fields in the above examples are string , error , int , P , M , and Header , respectively.

Which Types Can be Embedded?

An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T , and T itself may not be a pointer type. The current Go specification (version 1.15) says The above description is accurate before Go 1.9. However, with the introduction of type aliases in Go 1.9, the description becomes a little outdated and inaccurate. For example, the description doesn't include the case of the P field in the example in the last section. Here, the article tries to provide more accurate descriptions. A type name T can be embedded as an embedded field unless T denotes a defined pointer type or a pointer type which base type is either a pointer or an interface type.

can be embedded as an embedded field unless denotes a defined pointer type or a pointer type which base type is either a pointer or an interface type. A pointer type *T , where T is a type name denoting the base type of the pointer type, can be embedded as an embedded field unless type name T denotes a pointer or interface type. The following lists some example types which can and can't be embedded: type Encoder interface {Encode([]byte) []byte} type Person struct {name string; age int} type Alias = struct {name string; age int} type AliasPtr = *struct {name string; age int} type IntPtr *int type AliasPP = *IntPtr // These types and aliases can be embedded. Encoder Person *Person Alias *Alias AliasPtr int *int // These types and aliases can't be embedded. AliasPP // base type is a pointer type *Encoder // base type is an interface type *AliasPtr // base type is a pointer type IntPtr // defined pointer type *IntPtr // base type is a pointer type *chan int // base type is a non-defined type struct {age int} // non-defined non-pointer type map[string]int // non-defined non-pointer type []int64 // non-defined non-pointer type func() // non-defined non-pointer type Here, the article tries to provide more accurate descriptions.The following lists some example types which can and can't be embedded: No two fields are allowed to have the same name in a struct, there are no exceptions for anonymous struct fields. By the embedded field naming rules, a non-defined pointer type can't be embedded along with its base type in the same struct type. For example, int and *int can't be embedded in the same struct type.

A struct type can't embed itself or its aliases, recursively.

Generally, it is only meaningful to embed types who have fields or methods (the following sections will explain why), though some types without any field and method can also be embedded.

What Is the Meaningfulness of Type Embedding?

The main purpose of type embedding is to extend the functionalities of the embedded types into the embedding type, so that we don't need to re-implement the functionalities of the embedded types for the embedding type. Many other object-oriented programming languages use inheritance to achieve the same goal of type embedding. Both mechanisms have their own If a type T inherits another type, then type T obtains the abilities of the other type. At the same time, each value of type T can also be viewed as a value of the other type.

inherits another type, then type obtains the abilities of the other type. At the same time, each value of type can also be viewed as a value of the other type. If a type T embeds another type, then type other type becomes a part of type T , and type T obtains the abilities of the other type, but none values of type T can be viewed as values of the other type. Here is an example to show how an embedding type extends the functionalities of the embedded type. package main import "fmt" type Person struct { Name string Age int } func (p Person) PrintName() { fmt.Println("Name:", p.Name) } func (p *Person) SetAge(age int) { p.Age = age } type Singer struct { Person // extends Person by embedding it works []string } func main() { var gaga = Singer{Person: Person{"Gaga", 30}} gaga.PrintName() // Name: Gaga gaga.Name = "Lady Gaga" (&gaga).SetAge(31) (&gaga).PrintName() // Name: Lady Gaga fmt.Println(gaga.Age) // 31 } Many other object-oriented programming languages use inheritance to achieve the same goal of type embedding. Both mechanisms have their own benefits and drawbacks . Here, this article will not discuss which one is better. We should just know Go chose the type embedding mechanism, and there is a big difference between the two:Here is an example to show how an embedding type extends the functionalities of the embedded type. From the above example, it looks that, after embedding type Person , the type Singer obtains all methods and fields of type Person , and type *Singer obtains all methods of type *Person . Are the conclusions right? The following sections will answer this question. Please note that, a Singer value is not a Person value, the following code doesn't compile: var gaga = Singer{} var _ Person = gaga Please note that, avalue is not avalue, the following code doesn't compile:

Does the Embedding Type Obtain the Fields and Methods of the Embedded Types?

Singer and the methods of type *Singer used in the last example by using reflect standard package. package main import ( "fmt" "reflect" ) ... // the types declared in the last example func main() { t := reflect.TypeOf(Singer{}) // the Singer type fmt.Println(t, "has", t.NumField(), "fields:") for i := 0; i < t.NumField(); i++ { fmt.Print(" field#", i, ": ", t.Field(i).Name, "

") } fmt.Println(t, "has", t.NumMethod(), "methods:") for i := 0; i < t.NumMethod(); i++ { fmt.Print(" method#", i, ": ", t.Method(i).Name, "

") } pt := reflect.TypeOf(&Singer{}) // the *Singer type fmt.Println(pt, "has", pt.NumMethod(), "methods:") for i := 0; i < pt.NumMethod(); i++ { fmt.Print(" method#", i, ": ", pt.Method(i).Name, "

") } } The result: main.Singer has 2 fields: field#0: Person field#1: works main.Singer has 1 methods: method#0: PrintName *main.Singer has 2 methods: method#0: PrintName method#1: SetAge Let's list all the fields and methods of typeand the methods of typeused in the last example by using the reflection functionalities provided in thestandard package.The result: From the result, we know that the type Singer really owns a PrintName method, and the type *Singer really owns two methods, PrintName and SetAge . But the type Singer doesn't own a Name field. Then why is the selector expression gaga.Name legal for a Singer value gaga ? Please read the next section to get the reason.

Shorthands of Selectors

From the articles structs in Go and methods in Go, we have learned that, for a value x , x.y is called a selector, where y is either a field name or a method name. If y is a field name, then x must be a struct value or a struct pointer value. A selector is an expression, which represents a value. If the selector x.y denotes a field, it may also has its own fields (if x.y is a struct value) and methods. Such as x.y.z , where z can also be either a field name or a method name.

In Go, (without considering selector colliding and shadowing explained in a later section), if a middle name in a selector corresponds to an embedded field, then that name can be omitted from the selector. This is why embedded fields are also called anonymous fields.

package main type A struct { x int } func (a A) MethodA() {} type B struct { A } type C struct { B } func main() { var c C // The following 4 lines are equivalent. _ = c.B.A.x _ = c.B.x _ = c.A.x _ = c.x // x is called a promoted field of type C // The following 4 lines are equivalent. c.B.A.MethodA() c.B.MethodA() c.A.MethodA() c.MethodA() } For example: This is why the expression gaga.Name is legal in the example in the last section. For it is just the shorthand of gaga.Person.Name . Name is called a promoted field of type Singer . As any embedding type must be a struct type, and the article func main() { var c C pc = &c // The following 4 lines are equivalent. fmt.Println(pc.B.A.x) fmt.Println(pc.B.x) fmt.Println(pc.A.x) fmt.Println(pc.x) // The following 4 lines are equivalent. pc.B.A.MethodA() pc.B.MethodA() pc.A.MethodA() pc.MethodA() } As any embedding type must be a struct type, and the article structs in Go has mentioned that the field of an addressable struct value can be selected through the pointers of the struct value, so the following code is also legal in Go. Similarly, the selector gaga.PrintName can be viewed as a shorthand of gaga.Person.PrintName . But, it is also okay if we think it is not a shorthand. After all, the type Singer really has a PrintName method, though the method is declared implicitly (please read the section after next for details). For the similar reason, the selector (&gaga).PrintName and (&gaga).SetAge can also be viewed as, or not as, shorthands of (&gaga.Person).PrintName and (&gaga.Person).SetAge . Note, we can also use the selector gaga.SetAge , only if gaga is an addressable value of type Singer . It is just syntactical sugar of (&gaga).SetAge . Please read method calls for details. In the above examples, c.B.A.x is called the full form of selectors c.x , c.B.x and c.A.x . Similarly, c.B.A.MethodA is called the full form of selectors c.MethodA , c.B.MethodA and c.A.MethodA . If every middle name in the full form of a selector corresponds to an embedded field, then the number of middle names in the selector is called the depth of the selector. For example, the depth of the selector c.MethodA used in an above example is 2, for the full form of the selector is c.B.A.MethodA .

Selector Shadowing and Colliding

x (we should always assume it is addressable, even if it is not), it is possible that many of its full-form selectors have the same last item y and every middle name of these selectors represents an embedded field. For such cases, only the full-form selector with the shallowest depth (assume it is the only one) can be shortened as x.y . In other words, x.y denotes the full-form selector with the shallowest depth. Other full-form selectors are shadowed by the one with the shallowest depth.

. In other words, denotes the full-form selector with the shallowest depth. Other full-form selectors are by the one with the shallowest depth. if there are more than one full-form selectors with the shallowest depth, then none of those full-form selectors can be shortened as x.y . We say those full-form selectors with the shallowest depth are colliding with each other. For a value(we should always assume it is addressable, even if it is not), it is possible that many of its full-form selectors have the same last itemand every middle name of these selectors represents an embedded field. For such cases, If a method selector is shadowed by another method selector, and the two corresponding method signatures are identical, we say the first method is overridden by the other one. For example, assume A , B and C are three type A struct { x string } func (A) y(int) bool { return false } type B struct { y bool } func (B) x(string) {} type C struct { B } The following code doesn't compile. The reason is the depths of the selectors v1.A.x and v1.B.x are equal, so the two selectors collide with each other and neither of them can be shortened to v1.x . The same situation is for the selectors v1.A.y and v1.B.y . var v1 struct { A B } func f1() { _ = v1.x // error: ambiguous selector v1.x _ = v1.y // error: ambiguous selector v1.y } For example, assumeandare three defined types The following code doesn't compile. The reason is the depths of the selectorsandare equal, so the two selectors collide with each other and neither of them can be shortened to. The same situation is for the selectorsand The following code compiles okay. The selector v2.C.B.x is shadowed by v2.A.x , so the selector v2.x is a shortened form of v2.A.x actually. For the same reason, the selector v2.y is a shortened form of v2.A.y , not of v2.C.B.y . var v2 struct { A C } func f2() { fmt.Printf("%T

", v2.x) // string fmt.Printf("%T

", v2.y) // func(int) bool } The following code compiles okay. The selectoris shadowed by, so the selectoris a shortened form ofactually. For the same reason, the selectoris a shortened form of, not of Colliding or shadowed selectors don't prevent their deeper selectors being promoted. For example, the .M and .z selectors still get promoted in the following example. package main type x string func (x) M() {} type y struct { z byte } type A struct { x } func (A) y(int) bool { return false } type B struct { y } func (B) x(string) {} func main() { var v struct { A B } //_ = v.x // error: ambiguous selector v.x //_ = v.y // error: ambiguous selector v.y _ = v.M // ok. <=> v.A.x.M _ = v.z // ok. <=> v.B.y.z } Colliding or shadowed selectors don't prevent their deeper selectors being promoted. For example, theandselectors still get promoted in the following example. One detail which is unusual but should be noted is that two unexported methods (or fields) from two differnt packages are always viewed as two different identifiers, even if their names are identical. So they will not never collide with or shadow each other when their owner types are embedded in the same struct type. For example, a program comprising two packages as the following shows will compile and run okay. But if all the m() occurrences are replaced with M() , then the program will fail to compile for A.M and B.M collide with each other, so c.M is not a valid selector. package foo // x.y/foo import "fmt" type A struct { n int } func (a A) m() { fmt.Println("A", a.n) } type I interface { m() } func Bar(i I) { i.m() } package main import "fmt" import "x.y/foo" type B struct { n bool } func (b B) m() { fmt.Println("B", b.n) } type C struct{ foo.A B } func main() { var c C c.m() // B false foo.Bar(c) // A 0 } One detail which is unusual but should be noted is that two unexported methods (or fields) from two differnt packages are always viewed as two different identifiers, even if their names are identical. So they will not never collide with or shadow each other when their owner types are embedded in the same struct type. For example, a program comprising two packages as the following shows will compile and run okay. But if all theoccurrences are replaced with, then the program will fail to compile forandcollide with each other, sois not a valid selector.

Implicit Methods for Embedding Types

As mentioned above, both of type Singer and type *Singer have a PrintName method each, and the type *Singer also has a SetAge method. However, we never explicitly declare these methods for the two types. Where do these methods come from? In fact, assume a struct type S embeds a type (or an type alias) T and the embedding is legal, for each method of the embedded type T , if the selectors to that method neither collide with nor are shadowed by other selectors, then compilers will implicitly declare a corresponding method with the same prototype for the embedding struct type S . And consequently, compilers will also implicitly declare a corresponding method for the pointer type *S .

, if the selectors to that method neither collide with nor are shadowed by other selectors, then compilers will implicitly declare a corresponding method with the same prototype for the embedding struct type . And consequently, compilers will also implicitly declare a corresponding method for the pointer type . for each method of the pointer type *T , if the selectors to that method neither collide with nor are shadowed by other selectors, then compilers will implicitly declare a corresponding method with the same prototype for the pointer type *S . Simply speaking, type struct{T} and type *struct{T} both obtain all the methods of the type denoted by T .type *struct{T} .

and type both obtain all the methods of the type denoted by .type . type *struct{T} , type struct{*T} , and type *struct{*T} all obtain all the methods of type *T . The following methods are implicitly declared by compilers for type Singer and type *Singer . func (s Singer) PrintName() { s.Person.PrintName() // Compilers will make an optimization here, so // that only the Person part of the argument // passed to the parameter s is copied. } func (s *Singer) PrintName() { (*s).Person.PrintName() } func (s *Singer) SetAge(age int) { (&s.Person).SetAge(age) // <=> (&((*s).Person)).SetAge(age) } In fact, assume a struct typeembeds a type (or an type alias)and the embedding is legal,Simply speaking,The following methods are implicitly declared by compilers for typeand type The implicit methods can also be called promoted methods. From the article methods in Go, we know that we can't explicitly declare methods for non-defined struct types and non-defined pointer types whose base types are non-defined struct types. But through type embedding, such non-defined types can also own methods. Here is another example to show which implicit methods are declared. package main import "fmt" import "reflect" type F func(int) bool func (f F) Validate(n int) bool { return f(n) } func (f *F) Modify(f2 F) { *f = f2 } type B bool func (b B) IsTrue() bool { return bool(b) } func (pb *B) Invert() { *pb = !*pb } type I interface { Load() Save() } func PrintTypeMethods(t reflect.Type) { fmt.Println(t, "has", t.NumMethod(), "methods:") for i := 0; i < t.NumMethod(); i++ { fmt.Print(" method#", i, ": ", t.Method(i).Name, "

") } } func main() { var s struct { F *B I } PrintTypeMethods(reflect.TypeOf(s)) fmt.Println() PrintTypeMethods(reflect.TypeOf(&s)) } The result: struct { main.F; *main.B; main.I } has 5 methods: method#0: Invert method#1: IsTrue method#2: Load method#3: Save method#4: Validate *struct { main.F; *main.B; main.I } has 6 methods: method#0: Invert method#1: IsTrue method#2: Load method#3: Modify method#4: Save method#5: Validate Here is another example to show which implicit methods are declared.The result: If a struct type embeds a type which implements an interface type (the embedded type may be the interface type itself), then generally the struct type also implements the interface type, exception there is a method specified by the interface type shadowed by or colliding other methods or fields. For example, in the above example program, both the embedding struct type and the pointer type whose base type is the embedding struct type implement the interface type I . Please note, a type will only obtain the methods of the types it embeds directly or indirectly. In other words, the method set of a type is composed of the methods declared directly (either explicitly or implicitly) for the type and the method set of the type's underlying type. For example, in the following code, the type Age has no methods, for it doesn't embed any types.

has no methods, for it doesn't embed any types. the type X has two methods, IsOdd and Double . IsOdd is obtained by embedding the type MyInt .

has two methods, and . is obtained by embedding the type . the type Y has no methods, for its embedded the type Age has not methods.

has no methods, for its embedded the type has not methods. the type Z has only one method, IsOdd , which is obtained by embedding the type MyInt . It doesn't obtain the method Double from the type X , for it doesn't embed the type X . type MyInt int func (mi MyInt) IsOdd() bool { return mi%2 == 1 } type Age MyInt type X struct { MyInt } func (x X) Double() MyInt { return x.MyInt + x.MyInt } type Y struct { Age } type Z X Please note, a type will only obtain the methods of the types it embeds directly or indirectly. In other words, the method set of a type is composed of the methods declared directly (either explicitly or implicitly) for the type and the method set of the type's underlying type. For example, in the following code,

Interface Types Embed Interface Types

Not only can struct types embed other types, but also can interface types, but interface types can only embed interface types. Please read interfaces in Go for details.

An Interesting Type Embedding Example

package main type I interface { m() } type T struct { I } func main() { var t T var i = &t t.I = i i.m() // will call t.m(), then call i.m() again, ... } In the end, let's view an interesting example. The example program will dead loop and stack overflow. If you have understood the above content and polymorphism and type embedding, it is easy to understand why it will dead loop.