Анонимные поля структур

Анонимные поля в структурах Go позволяют встраивать одну структуру в другую, не указывая явное имя поля. При таком встраивании все поля вложенной структуры становятся доступными напрямую через внешнюю структуру. Это называется продвижением полей (field promotion). Анонимные поля широко используются для композиции - альтернативы наследованию в Go.

Синтаксис

gotype Inner struct {
  Field1 string
  Field2 int
}

type Outer struct {
  Inner // анонимное поле
  OwnField string
}

Пример

Давайте создадим две структуры и встроим одну в другую в качестве анонимного поля:

gopackage main

import "fmt"

type Address struct {
  City  string
  Street  string
  ZipCode int
}

type Person struct {
  Address // анонимное поле
  Name  string
  Age   int
}

func main() {
  p := Person{
    Address: Address{
      City:  "Moscow",
      Street:  "Tverskaya",
      ZipCode: 101000,
    },
    Name: "Alice",
    Age:  30,
  }

  fmt.Println(p.Name)
  fmt.Println(p.Age)
  fmt.Println(p.City)
  fmt.Println(p.Street)
  fmt.Println(p.ZipCode)
}

Результат выполнения кода:

go"Alice"
30
"Moscow"
"Tverskaya"
101000

Как видите, поля структуры Address доступны напрямую через переменную p без указания имени поля Address.

Пример

При конфликте имен приоритет имеет поле самой структуры. Давайте посмотрим на пример:

gopackage main

import "fmt"

type A struct {
  Value string
}

type B struct {
  Value int
}

type C struct {
  A
  B
  Value bool
}

func main() {
  c := C{
    A: A{Value: "hello"},
    B: B{Value: 42},
    Value: true,
  }

  fmt.Println(c.Value)  // поле самой структуры
  fmt.Println(c.A.Value) // поле из A
  fmt.Println(c.B.Value) // поле из B
}

Результат выполнения кода:

gotrue
"hello"
42

Пример

Анонимные поля могут быть не только структурами, но и другими типами:

gopackage main

import "fmt"

type MyString string

type MyInt int

type Container struct {
  MyString // анонимное поле типа MyString
  MyInt  // анонимное поле типа MyInt
  flag   bool
}

func main() {
  c := Container{
    MyString: "example",
    MyInt:  100,
    flag:   true,
  }

  fmt.Println(c.MyString)
  fmt.Println(c.MyInt)
  fmt.Println(c.flag)
}

Результат выполнения кода:

go"example"
100
true

Обратите внимание, что доступ к анонимным полям неструктурных типов осуществляется через имя типа.

Смотрите также