Go Structs
External
Internal
Overview
Structs are user-defined composite types, grouping together instances of arbitrary types, into one object.
A struct declaration consists in a series of fields, where each fields has an arbitrary name and a type. A struct may also contain other types, named embedded types and also methods that operate on the structure's fields. The fields usually represent a has-a relationship, consistent with the struct's composite type nature.
Structs can represent data values that could have either a primitive or non-primitive value. "Primitive" structs imply creating a new instance every time an existing value is mutated. In this case, values themselves, rather than pointers, are used to share values of those structs. An example is the Time
structure in the time
package. However, in most cases, structs exhibit a non-primitive structure: adding or removing something from the value mutates the value, does not create a new value.
Declaration
The struct type definition is introduced by the type
keyword, to indicate that this is a user-defined type, followed by the new type name and the keyword struct
, followed by a curly-brackets-enclosed enumeration of fields. Each field is defined by an arbitrary name and a type. The type can be a pre-declared type or a user-defined type, such as another struct
or an interface.
Struct types can be declared at package level or inside a function.
type Item struct {
color string
size int
}
Fields with the same types can be collapsed:
type SomeStruct struct {
...
i, j, k int
...
}
Literal
i := Item{color: "blue, size: 5}
Initialization
Initialize a struct variable with an empty struct using the new()
built-in function and the short variable declaration:
i := new(Item)
This results in an "empty" structure, with all fields initialized to zero.
A struct literal can also be used:
i := Item{color: "blue, size: 5}
Operators
The Dot Operator
Individual fields in a struct can be read and modified using the "dot notation":
var i Item
i.color = "blue"
i.size = 2
fmt.Printf("color %s, size %d\b", i.color, i.size)
Embedded Types
TO DISTRIBUTE
Initialization
Once the type has been defined, variables of that type can be declared using the long declaration or short declaration syntax, as shown below. More details about variable declaration can be found here:
Long Variable Declaration
var ms myStruct
If no explicit initialization follows, all the struct's fields are initialized with their zero value.
Short Variable Declaration
The short variable declaration uses the short variable declaration operator :=
Literal
Struct literal initialization comes in two forms.
1. All the values are specified on the same line:
ms := myStruct{i: 5, s: "something"}
or
2. Values are specified on separate lines:
ms := myStruct{ i: 5, s: "something", }
Note the trailing comma when using the multi-line literal.
There is a shorter struct literal where the name of the fields are omitted, provided that the order is maintained:
ms := myStruct{5, "something"}
Embedded Literals
When a field of a struct is another struct, embedded literals can be used in initialization:
a := A { b: B { d: "something", } c : "something else", }
new()
new() initialization:
msPtr := new(myStruct)
Note new() returns a pointer to the structure and not the structure itself.
Fields
Fields can be access with the . operator.
Note that the . operator works with a regular struct variable as well as with a pointer to a struct: the compiler knows how to compensate for both of these cases. Also see . used for field access.
ms := myStruct{1, "s"} msPtr := new(myStruct) // valid: ms.i // valid: msPtr.i
Even if the enclosing struct type is exported by a package, not all fields are exported automatically, only those whose first character is an upper case letter. This behavior makes possible to have "private" fields in a public structure, when the structure is used outside its package.
Field Tags and Attributes
A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored.
Example:
type A struct { name string `json:"name"` }
In the example above, tags have been included to provide metadata the JSON decoding function needs to parse JSON content. Each tag maps a field name in the struct type to a filed name in the JSON document.
Embedded Types
An embedded type is initialized by declaring a name of a struct inside other struct - without associating it with a field. An embedded type is sometimes referred to as anonymous field. It models an is-a relationship. Example:
type A struct { f1 int } type B struct { A f2 int }
Methods and Embedded Types
A pointer receiver method associated with the embedded type also works with the embedding type. For example, if there's a:
func (a *A) m1(...) { ... }
m1() also works directly with B instances as such:
bPtr := new(B) ... bPtr.m1(...)
In the code sequence above, the invocations bPtr.m1(...) and bPtr.A.m1(...) are equivalent.
Empty Structs
An empty struct allocates zero bytes when values of this type are created. They are useful when a type (but not state) is needed. Example:
// we declared an empty struct that defines the type "A" type A struct{}