Нулевые значения и значения по умолчанию
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 17 из 107.
В Go каждая переменная имеет нулевое значение — значение по умолчанию, присваиваемое при объявлении переменной без явной инициализации. Понимание нулевых значений необходимо для работы со структурами, так как неинициализированные поля автоматически получают эти значения по умолчанию.
У каждого типа есть своё нулевое значение:
| Тип | Нулевое значение |
|---|---|
| int, float64 | 0 |
| string | "" (пустая строка) |
| bool | false |
| pointer, slice, map | nil |
Когда вы создаете структуру, любое поле, которое вы не устанавливаете явно, получает свое нулевое значение (zero value).
type User struct {
Name string
Age int
Active bool
}
func main() {
var u User
fmt.Println(u.Name) // "" (empty string)
fmt.Println(u.Age) // 0
fmt.Println(u.Active) // false
}Это также относится к частичной инициализации. Только указанные вами поля получают пользовательские значения.
u := User{Name: "Alice"}
fmt.Println(u.Age) // 0
fmt.Println(u.Active) // false
Нулевые значения делают структуры пригодными для использования сразу, без явной инициализации. Однако будьте осторожны со ссылочными типами, такими как срезы и карты — их нулевым значением является nil, что может привести к панике во время выполнения, если вы попытаетесь использовать их без инициализации.
Задание
ЛегкоДавайте создадим систему профилей игроков, которая демонстрирует, как работают нулевые значения (zero values) в Go. Вы создадите игровой профиль, в котором некоторые поля заданы явно, а другие полагаются на свои значения по умолчанию.
Вы организуете свой код в двух файлах:
player.go: Определите структуруPlayerсо следующими полями:Username(string),Level(int),Score(int),IsPremium(bool) иGuildName(string). Также создайте методDisplayProfile, который возвращает отформатированную строку со всей информацией об игроке.main.go: Считайте имя пользователя из входных данных и создайте Player, используя частичную инициализацию — установите только полеUsername. Затем выведите полный профиль, чтобы увидеть, как Go заполняет неустановленные поля их нулевыми значениями.
Будут предоставлены следующие входные данные:
- Строка 1: Имя пользователя игрока
Ваш метод DisplayProfile должен возвращать строку именно в таком формате:
Username: [Username]
Level: [Level]
Score: [Score]
Premium: [IsPremium]
Guild: [GuildName]Например, если имя пользователя — ShadowKnight, ваш вывод должен содержать имя пользователя вместе со всеми нулевыми значениями для неинициализированных полей:
Username: ShadowKnight
Level: 0
Score: 0
Premium: false
Guild: Обратите внимание, что в поле Guild после двоеточия ничего не отображается — это нулевое значение пустой строки. Эта задача поможет вам увидеть, что именно Go присваивает каждому типу, когда вы не указываете явное значение.
Шпаргалка
В Go у каждой переменной есть нулевое значение (zero value) — значение по умолчанию, которое присваивается при объявлении переменной без явной инициализации.
У каждого типа есть свое нулевое значение:
| Тип | Нулевое значение |
|---|---|
| int, float64 | 0 |
| string | "" (пустая строка) |
| bool | false |
| pointer, slice, map | nil |
При создании структуры любое поле, которое вы не задали явно, получает свое нулевое значение:
type User struct {
Name string
Age int
Active bool
}
func main() {
var u User
fmt.Println(u.Name) // "" (пустая строка)
fmt.Println(u.Age) // 0
fmt.Println(u.Active) // false
}Частичная инициализация — только указанные поля получают пользовательские значения:
u := User{Name: "Alice"}
fmt.Println(u.Age) // 0
fmt.Println(u.Active) // falseНулевые значения делают структуры пригодными для использования сразу, без явной инициализации. Будьте осторожны со ссылочными типами, такими как слайсы (slices) и карты (maps) — их нулевое значение равно nil, что может привести к ошибкам во время выполнения (runtime panics), если использовать их без инициализации.
Попробуйте сами
package main
import (
"fmt"
)
func main() {
// Считать имя пользователя из ввода
var username string
fmt.Scanln(&username)
// TODO: Создать Player, используя частичную инициализацию
// Установите только поле Username, позвольте остальным полям использовать значения по умолчанию
// TODO: Отобразить профиль игрока, используя метод DisplayProfile
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool