Menu
Coddy logo textTech

Основы встраивания структур

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 35 из 107.

Встраивание структур — это механизм Go для включения одного типа структуры в другой. Вместо имени поля вы просто указываете тип, и Go делает fields встроенной структуры доступными во внешней структуре.

Вот базовый синтаксис:

type Address struct {
    City    string
    Country string
}

type Person struct {
    Name string
    Address  // встроенный - без имени поля
}

Когда вы встраиваете Address в Person, вы можете обращаться к встроенным полям напрямую через внешнюю структуру:

func main() {
    p := Person{
        Name: "Alice",
        Address: Address{
            City:    "London",
            Country: "UK",
        },
    }
    
    fmt.Println(p.City)     // London - прямой доступ
    fmt.Println(p.Country)  // UK - прямой доступ
    fmt.Println(p.Address.City)  // также работает
}

Обрати внимание, как p.City работает без явной записи p.Address.City. Go автоматически продвигает поля встроенной структуры, делая их доступными так, как будто они принадлежат внешней структуре. При необходимости к ним по-прежнему можно обращаться через имя встроенного типа.

Это отличается от обычных вложенных структур, где для доступа к внутренним fields всегда необходимо использовать имя field. Embedding создаёт более плоский и удобный API, сохраняя при этом логическую группировку связанных данных.

challenge icon

Задание

Легко

Давайте создадим систему регистрации транспортных средств, которая использует встраивание структур для создания чистой, организованной модели данных. Вы отделите контактную информацию от сведений о транспортном средстве, сохранив возможность direct доступа ко всем fields благодаря встраиванию.

Вы организуете свой код в двух файлах:

  • vehicle.go: создайте две структуры, которые взаимодействуют благодаря встраиванию:
    • структуру ContactInfo с fields OwnerName и Phone (обе строкового типа)
    • структуру Vehicle, которая встраивает ContactInfo (без имени field) и добавляет собственные fields Make, Model и Year
    Также создайте method с именем Summary для Vehicle, который возвращает formatted строку, содержащую всю информацию о транспортном средстве и контактах.
  • main.go: считайте сведения о транспортном средстве и owner из input, создайте Vehicle instance со встроенным ContactInfo и продемонстрируйте доступ к встроенным fields как direct, так и через имя встроенного типа. В конце выведите сводку о транспортном средстве.

Будут предоставлены следующие входные данные:

  • Строка 1: имя owner
  • Строка 2: номер телефона
  • Строка 3: Make транспортного средства
  • Строка 4: Model транспортного средства
  • Строка 5: год (целое число)

Ваш method Summary должен возвращать строку в следующем формате:

[Year] [Make] [Model] - Owner: [OwnerName], Phone: [Phone]

В основном файле продемонстрируйте продвижение field, выведя:

  1. имя owner, к которому выполнен direct доступ через Vehicle (например, v.OwnerName)
  2. номер телефона, к которому выполнен доступ через встроенный тип (например, v.ContactInfo.Phone)
  3. полную сводку из вашего method Summary

Например, если заданы Alice Smith, 555-1234, Toyota, Camry и 2023, результатом должен быть:

Alice Smith
555-1234
2023 Toyota Camry - Owner: Alice Smith, Phone: 555-1234

Обратите внимание, как работают оба способа доступа: direct доступ благодаря продвижению field и явный доступ через имя встроенного типа, что дает вам гибкость при работе со встроенными данными.

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Прочитать имя владельца
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)

	// Прочитать номер телефона
	phone, _ := reader.ReadString('\n')
	phone = strings.TrimSpace(phone)

	// Прочитать марку автомобиля
	make, _ := reader.ReadString('\n')
	make = strings.TrimSpace(make)

	// Прочитать модель автомобиля
	model, _ := reader.ReadString('\n')
	model = strings.TrimSpace(model)

	// Прочитать год
	yearStr, _ := reader.ReadString('\n')
	yearStr = strings.TrimSpace(yearStr)
	year, _ := strconv.Atoi(yearStr)

	// TODO: Создать экземпляр Vehicle со встроенным ContactInfo
	// Использовать значения, прочитанные из ввода выше

	// TODO: Вывести имя владельца, доступное напрямую на Vehicle (продвижение полей)
	// Пример: fmt.Println(v.OwnerName)

	// TODO: Вывести телефон, доступный через имя встроенного типа
	// Пример: fmt.Println(v.ContactInfo.Phone)

	// TODO: Вывести полное резюме, используя метод Summary
	// Пример: fmt.Println(v.Summary())

	// Удалите эти строки, как только реализуете решение
	_ = ownerName
	_ = phone
	_ = make
	_ = model
	_ = year
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Go