Модуль
1map2Массивы3Слайсы4Структуры← вы здесь
Урок 4~12 минут

Структуры

Объявление структуры

go
type Person struct {
    Name string
    Age  int
    Email string
}

Создание

go
// Именованный литерал — предпочтительно
p := Person{
    Name:  "Алиса",
    Age:   30,
    Email: "alice@example.com",
}
 
// Позиционный — хрупко, избегай
p2 := Person{"Боб", 25, "bob@example.com"}
 
// Нулевая структура
var p3 Person
fmt.Println(p3.Name) // ""
fmt.Println(p3.Age)  // 0
 
// Указатель через new
p4 := new(Person)    // *Person, все поля = zero value
p5 := &Person{Name: "Карл"} // *Person с инициализацией

Методы

Методы — функции с получателем (receiver):

go
func (p Person) Greet() string {
    return fmt.Sprintf("Привет, я %s!", p.Name)
}
 
func (p *Person) Birthday() {
    p.Age++
}
 
alice := Person{Name: "Алиса", Age: 30}
fmt.Println(alice.Greet()) // Привет, я Алиса!
alice.Birthday()
fmt.Println(alice.Age) // 31

Value receiver (p Person) — получает копию, не может изменить оригинал. Pointer receiver (p *Person) — получает указатель, изменения видны снаружи.

Правило: если хотя бы один метод требует pointer receiver — делай все методы pointer receiver.


Конструкторы

В Go нет new как в C++/Java. Конструктор — просто функция:

go
func NewPerson(name string, age int) *Person {
    if age < 0 {
        age = 0
    }
    return &Person{
        Name: name,
        Age:  age,
    }
}
 
alice := NewPerson("Алиса", 30)

Возвращай *T — дешевле копирования, и позволяет вернуть nil при ошибке.


Встраивание (Embedding)

Встраивание — «наследование» методов без наследования классов:

go
type Animal struct {
    Name string
}
 
func (a Animal) Speak() string {
    return a.Name + " говорит"
}
 
type Dog struct {
    Animal       // встроен без имени поля
    Breed string
}
 
d := Dog{
    Animal: Animal{Name: "Рекс"},
    Breed:  "Хаски",
}
 
fmt.Println(d.Speak()) // Рекс говорит — метод Animal доступен напрямую
fmt.Println(d.Name)    // Рекс — поле Animal тоже

Dog может переопределить Speak():

go
func (d Dog) Speak() string {
    return d.Name + " лает: Гав!"
}

Struct tags

Теги — метаданные, читаемые через reflection. Используются encoding/json, ORM-библиотеками, валидаторами:

go
type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email,omitempty"`
    Password string `json:"-"`            // никогда не сериализовать
}
 
u := User{ID: 1, Name: "Алиса", Email: "alice@example.com"}
data, _ := json.Marshal(u)
fmt.Println(string(data))
// {"id":1,"name":"Алиса","email":"alice@example.com"}
  • omitempty — пропустить если поле пустое
  • - — всегда пропускать

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

go
// Одноразовые структуры — не нужно объявлять тип
point := struct {
    X, Y int
}{X: 10, Y: 20}
 
// Полезно в тестах
tests := []struct {
    input    int
    expected int
}{
    {2, 4},
    {3, 9},
    {4, 16},
}

Сравнение структур

Структуры сравниваемы если все поля comparable:

go
type Point struct{ X, Y int }
 
p1 := Point{1, 2}
p2 := Point{1, 2}
p3 := Point{3, 4}
 
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false

Структуры со слайсами или map — не сравниваемы через ==.

Структура с методом-получателем — это почти объект. Но в Go нет наследования, только встраивание (embedding).
КОД
type Person struct {
    Name string
    Age  int
}

// Value receiver — получает КОПИЮ
func (p Person) Birthday() {
    p.Age++  // меняет копию, не оригинал
}

// Pointer receiver — получает УКАЗАТЕЛЬ
func (p *Person) Birthday() {
    p.Age++  // меняет оригинал через указатель
}
ОРИГИНАЛ В ПАМЯТИ
person (0x0042)
Name:"Алиса"
Age:30
КОПИЯ (только при value receiver)
p (копия на стеке)
Name:"Алиса"
Age:?
копии нет
Value receiver (p Person)
Получает КОПИЮ структуры
Оригинал не изменяется
Подходит для чтения данных
Меньше накладных расходов для маленьких структур
Pointer receiver (p *Person)
Получает УКАЗАТЕЛЬ на оригинал
Может изменять оригинал
Нужен для мутирующих методов
Обязателен для больших структур (экономия копирования)
🎯
Миссия 1 из 4
В чём разница между value receiver и pointer receiver?