Structs

Go’s structs are typed collections of fields. They’re useful for grouping data together to form records.

type Entry struct {
	Key   string
	Value int
}

var entry Entry // empty struct
  • struct являются значениями

  • При присваивании := struct полностью копируется

  • переменные типа struct не могут иметь ссылку на nil

  • The number of fields of a struct type can be zero.

  • var entry Entry - создаст структуру со значениями равными значению по умолчанию для своего типа, то есть var entry Entry = Entry {Key: "", Value: 0}.

  • A struct type can't have a field of the struct type itself, neither directly nor recursively.

Сравнение:

  • struct сравниваются по значению. Две структуры считаются равными если они имеют одинаковые поля.

  • Whether or not a struct is comparable depends on the struct’s fields. Structs that are entirely composed of comparable types are comparable; those with slice or map fields are not (function and channel fields also prevent a struct from being comparable).

  • If two struct variables are being compared and at least one of them has a type that’s an anonymous struct, you can compare them without a type conversion if the fields of both structs have the same names, order, and types.

Доступ

  • Struct fields are accessed using a dot.

  • Structs are mutable.

  • You can also use dots with struct pointers - the pointers are automatically dereferenced.

  • You can list just a subset of fields by using the Name: syntax. (And the order of named fields is irrelevant.)

  • Структура типа S не может содержать поле такого же типа S (агрегатное значение не может содержать само себя), но может объявить поле с типом указателя на *S.

var config struct {
    APIKey      string
    OAuthConfig oauth.Config
}

config.APIKey = "BADC0C0A"

Test tables:

var indexRuneTests = []struct {
    s    string
    rune rune
    out  int
}{
    {"a A x", 'A', 2},
    {"some_text=some_value", '=', 9},
    {"☺a", 'a', 3},
    {"a☻☺b", '☺', 4},
}

When a struct value is assigned to another struct value, the effect is the same as assigning each field one by one.

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
}

Embedded structures

Struct types have the ability to contain anonymous or embedded fields. This is also called embedding a type. When we embed a type into a struct, the name of the type acts as the field name for what is then an embedded field.

type User struct {
    Name string
    Email string
}

type Admin struct {
    User
    Level string
}

func main() {
    admin := Admin{
        User: User{
            Name:  "john smith",
            Email: "john@email.com",
        },
        Level: "super",
    }

    fmt.Println(admin.Name) // john smith
}

We have declared a new type called Admin and embedded the User type within the struct declaration. This is not inheritance but composition. There is no relationship between the User and the Admin type.

The type that is embedded is then called an inner type of the new outer type. Through inner type promotion, identifiers from the inner type are promoted up to the outer type. These promoted identifiers become part of the outer type as if they were declared explicitly by the type itself. The outer type is then composed of every- thing the inner type contains, and new fields and methods can be added. We still can access the inner type's method directly.

admin.User.Name
type Person struct {
	Name string
	Age  int
}

type Singer struct {
	Person // extends Person by embedding it
	works  []string
}

var gaga = Singer{Person: Person{"Gaga", 30}}

Please note that, a Singer value is not a Person value, the following code doesn't compile:

var gaga = Singer{}
var _ Person = gaga

Embedding an interface in a struct automatically defines all of the interface’s methods on the struct. It doesn’t provide any implementations of those methods, so you need to implement the methods that you care about.

Methods for embedded types

Для встроенных структур работает следующее правило: метод, определенный на User будет так же применим Admin, поскольку User встроен в Admin (обратное неверно):

func (u *User) Notify() {
    log.Printf("User: Sending User Email To %s<%s>\n",
        u.Name,
        u.Email)
}

func main() {
    admin := &Admin{
        User: User{
            Name:  "john smith",
            Email: "john@email.com",
        },
        Level: "super",
    }
    admin.Notify() // User: Sending User Email To john smith<john@email.com>
}

Function overloading for embedded structures

Переопределение функций работает в Go для разных типов структур:

func (u User) GetName() string {
    return u.Name
}

func (u Admin) GetName() string {
    return "ADMIN"
}

Functional Fields

Полями структур могут быть методы

Anonymous Struct Types

Anonymous struct types are allowed to be used as the types of the fields of another struct type. Anonymous struct type literals are also allowed to be used in composite literals.

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,
}

Struct tags

Last updated