struct
keyword which is followed by a sequence of field definitions enclosed in a {}
. Generally, each field definition is composed of a name and a type. The number of fields of a struct type can be zero.
struct {
title string
author string
pages int
}
title
and author
are both string
. The type of the pages
field is int
.
struct {
title, author string
pages int
}
"..."
). For example:
struct {
Title string `json:"title" myfmt:"s1"`
Author string `json:"author,omitempty" myfmt:"s2"`
Pages int `json:"pages,omitempty" myfmt:"n1"`
X, Y bool `myfmt:"b1"`
}
X
and Y
fields in the above example are identical (though using field tags as this way is a bad practice).
encoding/json
standard package to determine the field names in JSON texts, in the process of encoding struct values into JSON texts or decoding JSON texts into struct values. The functions in the encoding/json
standard package will only encode and decode the exported struct fields, which is why the first letters of the field names in the above example are all upper cased.
T{...}
, where T
must be a type literal or a type name, is called a composite literal and is used as the value literals of some kinds of types, including struct types and the container types introduced later.
T{...}
is a typed value, its type is T
.
S
whose underlying type is struct{x int; y bool}
, the zero value of S
can be represented by the following two variants of struct composite literal forms:
S{0, false}
. In this variant, no field names are present but all field values must be present by the field declaration orders.
S{x: 0, y: false}
, S{y: false, x: 0}
, S{x: 0}
, S{y: false}
and S{}
. In this variant, each field item is optional and the order of the field items is not important. The values of the absent fields will be set as the zero values of their respective types. But if a field item is present, it must be presented with the FieldName: FieldValue
form. The order of the field items in this form doesn't matter. The form S{}
is the most used zero value representation of type S
.
S
is a struct type imported from another package, it is recommended to use the second form, to maintain compatibility. Consider the case where the maintainer of the package adds a new field for type S
, this will make the use of first form invalid.
v
of type S
, we can use v.x
and v.y
, which are called selectors (or selector expressions), to represent the field values of v
. v
is called the receiver of the selectors.
.
in a selector as the property selection operator.
package main
import (
"fmt"
)
type Book struct {
title, author string
pages int
}
func main() {
book := Book{"Go 101", "Tapir", 256}
fmt.Println(book) // {Go 101 Tapir 256}
// Create a book value with another form.
// All of the three fields are specified.
book = Book{author: "Tapir", pages: 256, title: "Go 101"}
// None of the fields are specified. The title and
// author fields are both "", pages field is 0.
book = Book{}
// Only specify the author field. The title field
// is "" and the pages field is 0.
book = Book{author: "Tapir"}
// Initialize a struct value by using selectors.
var book2 Book // <=> book2 := Book{}
book2.author = "Tapir Liu"
book2.pages = 300
fmt.Println(book2.pages) // 300
}
,
in a composite literal is optional if the last item in the literal and the closing }
are at the same line. Otherwise, the last ,
is required. For more details, please read line break rules in Go.
var _ = Book {
author: "Tapir",
pages: 256,
title: "Go 101", // here, the "," must be present
}
// The last "," in the following line is optional.
var _ = Book{author: "Tapir", pages: 256, title: "Go 101",}
func f() {
book1 := Book{pages: 300}
book2 := Book{"Go 101", "Tapir", 256}
book2 = book1
// The above line is equivalent to the
// following lines.
book2.title = book1.title
book2.author = book1.author
book2.pages = book1.pages
}
package main
import "fmt"
func main() {
type Book struct {
Pages int
}
var book = Book{} // book is addressable
p := &book.Pages
*p = 123
fmt.Println(book) // {123}
// The following two lines fail to compile, for
// Book{} is unaddressable, so is Book{}.Pages.
/*
Book{}.Pages = 123
p = &(Book{}.Pages) // <=> p = &Book{}.Pages
*/
}
.
in a selector is higher than the address-taking operator &
.
package main
func main() {
type Book struct {
Pages int
}
// Book{100} is unaddressable but can
// be taken address.
p := &Book{100} // <=> tmp := Book{100}; p := &tmp
p.Pages = 200
}
(*bookN).pages
could be written as bookN.pages
. In other words, bookN
is dereferenced in the simplified selectors.
package main
func main() {
type Book struct {
pages int
}
book1 := &Book{100} // book1 is a struct pointer
book2 := new(Book) // book2 is another struct pointer
// Use struct pointers as structs.
book2.pages = book1.pages
// This last line is equivalent to the above line.
// In other words, if the receiver is a pointer,
// it will be implicitly dereferenced.
(*book2).pages = (*book1).pages
}
_
) are incomparable.
_
will be ignored.
S1
and S2
can be converted to each other's types, if S1
and S2
share the identical underlying type (by ignoring field tags). In particular if either S1
or S2
is an unnamed type and their underlying types are identical (considering field tags), then the conversions between the values of them can be implicit.
S0
, S1
, S2
, S3
and S4
in the following code snippet,
S0
can't be converted to the other four types, and vice versa, because the corresponding field names are different.
S1
, S2
, S3
and S4
can be converted to each other's type.
S2
can be implicitly converted to type S3
, and vice versa.
S2
can be implicitly converted to type S4
, and vice versa.
S2
must be explicitly converted to type S1
, and vice versa.
S3
must be explicitly converted to type S4
, and vice versa.
package main
type S0 struct {
y int "foo"
x bool
}
// S1 is an alias of an unnamed type.
type S1 = struct {
x int "foo"
y bool
}
// S2 is also an alias of an unnamed type.
type S2 = struct {
x int "bar"
y bool
}
// If field tags are ignored, the underlying
// types of S3(S4) and S1 are same. If field
// tags are considered, the underlying types
// of S3(S4) and S1 are different.
type S3 S2 // S3 is a defined (so named) type
type S4 S3 // S4 is a defined (so named) type
var v0, v1, v2, v3, v4 = S0{}, S1{}, S2{}, S3{}, S4{}
func f() {
v1 = S1(v2); v2 = S2(v1)
v1 = S1(v3); v3 = S3(v1)
v1 = S1(v4); v4 = S4(v1)
v2 = v3; v3 = v2 // the conversions can be implicit
v2 = v4; v4 = v2 // the conversions can be implicit
v3 = S3(v4); v4 = S4(v3)
}
var aBook = struct {
// The type of the author field is
// an anonymous struct type.
author struct {
firstName, lastName string
gender bool
}
title string
pages int
}{
author: struct { // an anonymous struct type
firstName, lastName string
gender bool
}{
firstName: "Mark",
lastName: "Twain",
},
title: "The Million Pound Note",
pages: 96,
}
The Go 101 project is hosted on Github. Welcome to improve Go 101 articles by submitting corrections for all kinds of mistakes, such as typos, grammar errors, wording inaccuracies, description flaws, code bugs and broken links.
If you would like to learn some Go details and facts every serveral days, please follow Go 101's official Twitter account @zigo_101.
reflect
standard package.sync
standard package.sync/atomic
standard package.