The Go Programming Language Specification
Struct types
A struct is a sequence of named elements, called fields, each of
which has a name and a type. Field names may be specified explicitly
(IdentifierList) or implicitly (EmbeddedField). Within a struct,
non-blank field names must be unique.
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
A field declared with a type but no explicit field name is called an
embedded field. 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 unqualified type name acts as the field name.
A field or method f of an embedded field in a struct x is called
promoted if x.f is a legal selector that denotes that field or method
f.
Promoted fields act like ordinary fields of a struct except that they
cannot be used as field names in composite literals of the struct.
Given a struct type S and a type named 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.
Use an embedded field of a struct
. For example,
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Load(k)
fmt.Println(k, v, ok)
}
Playground: https://play.golang.org/p/YCNeiYVhlT
Output:
true
test 42 true
The Go Programming Language Specification
Selectors
For a primary expression x that is not a package name, the selector
expression
x.f
denotes the field or method f of the value x (or sometimes *x; see
below). The identifier f is called the (field or method) selector; it
must not be the blank identifier. The type of the selector expression
is the type of f. If x is a package name, see the section on qualified
identifiers.
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. The
number of embedded fields traversed to reach f is called its depth in
T. The depth of a field or method f declared in T is zero. The depth
of a field or method f declared in an embedded field A in T is the
depth of f in A plus one.
Rule 1:
For a value x of type T or *T where T is not a pointer or interface
type, x.f denotes the field or method at the shallowest depth in T
where there is such an f. If there is not exactly one f with
shallowest depth, the selector expression is illegal.
Sometimes, there is ambiguity in complex cases of nested embedding. If so, specify the full qualifiers explicitly. For example, m.Map.LoadOrStore
and x.Map.Load
.
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.Map.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Map.Load(k)
fmt.Println(k, v, ok)
}