Go Structs Embedded Fields

From NovaOrdis Knowledge Base
Revision as of 02:10, 4 November 2024 by Ovidiu (talk | contribs) (Created page with "=Internal= =Overview= =TO DEPLETE= <font color=darkkhaki> Field embedding is used to share state in inheritance. When only the type but not the name of a filed is declared, the name of the field is implicitly the unqualified name of the type, and the field is called an '''embedded field''' or an anonymous field: <syntaxhighlight lang='go'> type SomeInterface interface { ... } type SomeOtherStruct struct { s...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Internal

Overview

TO DEPLETE

Field embedding is used to share state in inheritance. When only the type but not the name of a filed is declared, the name of the field is implicitly the unqualified name of the type, and the field is called an embedded field or an anonymous field:

type SomeInterface interface {
   ...
}

type SomeOtherStruct struct {
   s string
}

type Item struct {
	SomeInterface
    SomeOtherStruct
	int
}

Embedded fields, unlike named fields, model an is-a relationship.

An embedded field can be a type name T, a pointer to a non-interface type name (*T), and T itself may not be a pointer type. As mentioned above, the unqualified type name becomes the implicit field name. The previous example declares three embedded fields, one of type int, one of type SomeInterface, which is an interface declared somewhere in the package and the third of type SomeOtherStruct, which is a struct type declared somewhere else in the package. The type renders as:

{SomeInterface:<nil> SomeOtherStruct:{s:} int:0}

Note that if an embedded field is specified using the package and the type name (the qualified type name), the implicit field name is the unqualified type name.

Embedded Field Promotion

The embedded field's type identifiers are promoted to the embedding type, so they can be accessed as it would belong to the embedding type. Promotion also applies to methods associated with the embedded type. A method associated with the embedded type works with the embedding type. This strengthens the point that embedded fields model an "is-a" relationship, and elevates the field embedding mechanism to a sort of inheritance mechanism. Type embedding is the Go's "extends". It allows types to extend, and it changes their behavior.

Field promotion:

type Animal struct {
	name string
}

type Dog struct {
	Animal
}

dog := &Dog{Animal{"Fido"}}

...

fmt.Printf("name: %s\n", dog.name) // the "name" field is promoted into the Dog structure

Method promotion, for the same structs Animal and Dog declared above:

func (a *Animal) Move() {
	fmt.Printf("%s moves\n", a.name)
}

...

dog.Move() // Displays "Fido moves"

In the example above, the invocations dog.Move() and dog.Animal.Move() are equivalent.

If an interface is implemented by the embedded type, it is promoted to the embedding type.

Also see:

structs as Receiver Types

TODO: https://go.dev/ref/spec#Struct_types

Embedded Field Identity

The embedded field always exists in and of itself. It never loses its identity and it can be always accessed directly:

dog.Animal.name

Overriding Embedded Fields

The embedding type can override the embedding field elements, and reuse the identifiers, associate them with other types, etc. Both fields and methods can be overridden. This behavior provides polymorphism.

type Animal struct {
	name string
}

func (a *Animal) Move() {
	fmt.Printf("%s moves\n", a.name)
}

type Dog struct {
	Animal
}

func (d *Dog) Move() {
	fmt.Printf("%s jumps\n", d.name)
}

...
dog := &Dog{Animal{"Fido"}}
dog.Move() // will print "Fido jumps"

When the embedding type does not want to implement an embedded type interface, it can override at least one of the method of the embedded type method set. Example required.