#15 golang Структуры - композиция структур, именнованная, встраивание, перекрытие полей
Primary tabs
Forums:
Структуры в Go — это составные типы данных с набором полей, похожие на классы в PHP или Python.
Подобно объявлению простых пользовательских типов мы используем ключевое слово type для определения конкретного типа структуры:
type Person struct {
Id int
Name string
IsActive bool
}
-- где Person - имя объявленного типа. Тут у нас имеются типа поля разных типов.
Инициализация структур
Создавать структуры мы можем, используя явное указание имен полей, или же только задавая значения (строго в порядке объявления):
type Person struct {
Id int
Name string
IsActive bool
}
func main() {
// явное задание полей:
Petya := Person{
Id: 1,
Name: "Петя",
IsActive: true,
}
fmt.Println(Petya)
// перечисляем только значения
Vasya := Person{
1,
"Вася",
true,
}
fmt.Println(Vasya)
}
-- когда мы явно указываем поля, мы можем задавать не все значения, тогда незаданные поля получат значения по умолчанию.
А вот для способа с передачей только значений уже потребуется указывать вообще все значения.
Обращение к полям структуры
Обращение в полям, как и следовало ожидать, происходит через точку:
type Person struct {
Id int
Name string
IsActive bool
}
func main() {
Petya := Person{
Id: 1,
Name: "Петя",
IsActive: true,
}
fmt.Println(Petya.Name) // распечатаем поле имени
}
Видимость полей
Первая буква имени поля подчиняется общему правилу видимости: с заглавной буквы — поле экспортируемое, то есть доступное и из других пакетов, со строчной — неэкспортируемое, видимое только внутри своего пакета:
type Account struct {
Login string // с заглавной - экспортируемое поле
balance int // со строчной - видно только внутри своего пакета
}
из другого пакета можно читать и менять acc.Login, а обращение к acc.balance просто не скомпилируется.
Во всех примерах этого урока поля объявлены с заглавной буквы не случайно — такие структуры удобно объявить в одном пакете и использовать в другом (например, в main).
Копозиция структур
В Go нет ООП (!) в классическом понимании, однако вся работа с объектами построена на композиции.
Именованная композиция
Мы можем встроить одну структуру в другую либо через явно объявление поле, которое тоже является структурой:
type Person struct {
Id int
Name string
IsActive bool
}
// копозиция через свойство
type Address struct {
Address string
Owner Person // тоже структура
}
func main() {
myAddress := Address{
Address: "Улица Лизюкова",
Owner: Person{
Id: 1,
Name: "Петя",
IsActive: true,
}}
fmt.Println(myAddress) // {Улица Лизюкова {1 Петя true}}
// Обращение к полю поля:
fmt.Println(myAddress.Owner.Name) // Петя
}
Композиция "встраиванием" (embedding)
Либо композицию можно провести "слиянием" структур, для этого тип указывается тоже как очередное поле, но без указание имени поля:
type Person struct {
Id int
Name string
IsActive bool
}
// копозиция через встраивание (embedding)
type Address struct {
Address string
Person // тоже структура, но встроенная
}
func main() {
myAddress := Address{
Address: "улица генерала Лизюкова",
Person: Person{
Id: 1,
Name: "Петя",
IsActive: true,
},
}
fmt.Println(myAddress) // {улица генерала Лизюкова {1 Петя true}}
// Обращение к полю как к своему:
fmt.Println(myAddress.Name) // Петя
}
-- при этом, не смотря на то, что поля дочерней структуры становятся "напрямую" родительскими литерально присвоить их на первом уровнем мы не можем, такой код для примера выше не сработает:
myAddress := Address{
Address: "улица генерала Лизюкова",
Id: 1, // "неизвестное" поле
Name: "Петя", // "неизвестное" поле
IsActive: true, // "неизвестное" поле
}
-- дело в том, что прямое присваивание не явно своих полей на первом уровне (а вообще говоря - на том же уровне, что и своих) запрещено, так как встроенная структура — это отдельный тип (а в Go всё с типами строго), а не просто набор полей, что предотвращает конфликты имен и делает структуру данных явной.
В т.ч. при объединении структур встраиванием (как в примере выше)
Выбор значения при встраивании -объединении (слиянии) структур с одинаковыми именами полей
Бывает так, что мы пытаемся объединить встраиванием структуры, у которых есть поля с одинаковым названием.
type Person struct {
Id int
Name string
IsActive bool
}
type Address struct {
Address string
Name string // еще одно поле с именем Name
Person // встроенная структура
}
func main() {
myAddress := Address{
Address: "улица генерала Лизюкова",
Name: "Мой адрес",
Person: Person{
Id: 1,
Name: "Петя",
IsActive: true,
},
}
fmt.Println(myAddress) // Тут получим:
// {улица генерала Лизюкова Мой адрес {1 Петя true}}
// -- видим, что оба поля сохранениы, но при
// обращении с первого уроня
// выводится будет поле из родительской структуры, не вложенной:
fmt.Println(myAddress.Name) // Мой адрес
// но мы всё равно можем достать вложенное поле
// Name через полный селектор ()
fmt.Println(myAddress.Person.Name) // Петя
}
-- в таком случае никакого конфликта не будет, и оба поля сохраняются, а при обращении к этому полю приоритет будет отдан наиболее "верхнему" (по вложенности структур одной в другую) полю структуры.
То есть при выполнении fmt.Println(myAddress.Name) выше будет выведено поле структуры Address, а не Person, но, как показано выше, через упоминание названия типа вложенной струкутры, мы можем достать и вложенное поле Name ;)
Видео-материалы
- : ВкВидео | Ютуб | Телеграм
Дополнительные материалы
- Структуры как поля других структур: https://metanit.com/go/tutorial/4.3.php
- Log in to post comments
- 396 reads
vedro-compota
Thu, 03/19/2026 - 00:10
Permalink
почему нельзя присваивать поля встраивания структур на первом ур
разберем этот вопрос выше
_____________
матфак вгу и остальная классика =)
vedro-compota
Thu, 03/19/2026 - 00:44
Permalink
Нельзя смешивать стили инициллизации -- либо называем все поля
Либо называем все поля либо нет:
func main() { // либо называя поля myAddress := Address{ Address: "улица генерала Лизюкова", Person: Person{ 1, "Петя", true, }, } //либо не называя их myAddress2 := Address{ "улица генерала Лизюкова", Person{ 1, "Петя", true, }, } fmt.Println(myAddress, myAddress2) }-- оба эти варианта рабочие, а вот так не сработает:
myAddress := Address{ Address: "улица генерала Лизюкова", Person{ // нет названия поля, а для предыдущего есть 1, "Петя", true, }, }_____________
матфак вгу и остальная классика =)