Что такое zero value? Какие zero value имеют основные типы?
Zero value — это нулевое значение, которое Go автоматически присваивает переменной, если при её создании не было указано начальное значение.
var count int
var name string
var active bool
fmt.Println(count) // 0
fmt.Println(name) // ""
fmt.Println(active) // falseВ Go переменная всегда содержит корректное значение своего типа — неинициализированных значений со случайными данными из памяти нет.
Zero values основных типов
| Тип | Zero value |
|---|---|
bool | false |
int, uint и другие целые числа | 0 |
float32, float64 | 0.0 |
complex64, complex128 | 0 + 0i |
string | "" |
указатель *T | nil |
слайс []T | nil |
мапа map[K]V | nil |
канал chan T | nil |
функция func | nil |
| интерфейс | nil |
массив [N]T | массив из zero values типа T |
| структура | структура, где каждое поле содержит свой zero value |
Эти значения определены спецификацией Go.
Пример
type User struct {
Name string
Age int
Active bool
Tags []string
}
var user User
fmt.Println(user.Name) // ""
fmt.Println(user.Age) // 0
fmt.Println(user.Active) // false
fmt.Println(user.Tags) // []
fmt.Println(user.Tags == nil) // trueКаждое поле структуры получает zero value своего типа.
Особенности ссылочных типов
Слайс
Zero value слайса — nil. Его длина и ёмкость равны нулю, но с ним можно безопасно использовать range и append.
var numbers []int
fmt.Println(numbers == nil) // true
fmt.Println(len(numbers)) // 0
numbers = append(numbers, 10)
fmt.Println(numbers) // [10]nil-слайс и созданный пустой слайс — не одно и то же:
var first []int
second := []int{}
fmt.Println(first == nil) // true
fmt.Println(second == nil) // falseПри этом оба имеют длину 0.
Мапа
Zero value мапы — nil.
Из nil-мапы можно читать:
var users map[string]int
fmt.Println(users["Alice"]) // 0Если ключа нет, Go возвращает zero value типа значения мапы:
age, exists := users["Alice"]
fmt.Println(age) // 0
fmt.Println(exists) // falseНо запись в nil-мапу вызывает panic:
var users map[string]int
// users["Alice"] = 30 // panicПеред записью мапу нужно создать:
users = make(map[string]int)
users["Alice"] = 30Указатель
Zero value указателя — nil.
var pointer *int
fmt.Println(pointer == nil) // trueРазыменование nil-указателя вызывает panic:
// fmt.Println(*pointer) // panicКанал
Zero value канала — nil.
var ch chan intОтправка данных в nil-канал и чтение из него блокируются, потому что такой канал не готов к передаче данных:
// ch <- 10
// value := <-chРабочий канал создаётся через make:
ch := make(chan int)Функция
Zero value функции — nil.
var handler func()
fmt.Println(handler == nil) // trueВызов nil-функции приводит к panic:
// handler() // panicИнтерфейс
Zero value интерфейса — nil.
var err error
fmt.Println(err == nil) // trueИнтерфейс равен nil, только когда внутри него нет ни конкретного типа, ни значения.
var pointer *MyError = nil
var err error = pointer
fmt.Println(err == nil) // falseЗдесь интерфейс содержит тип *MyError, поэтому сам интерфейс не равен nil.
Массивы и структуры
В массиве каждый элемент получает zero value своего типа:
var numbers [3]int
var names [2]string
fmt.Println(numbers) // [0 0 0]
fmt.Println(names) // ["" ""]В структуре zero value получает каждое поле:
type Config struct {
Port int
Address string
Enabled bool
}
var config Config
// Config{
// Port: 0,
// Address: "",
// Enabled: false,
// }Итог
Zero value — это автоматически установленное начальное значение типа.
Основные правила:
bool → false
numbers → 0
string → ""
*T → nil
[]T → nil
map[K]V → nil
chan T → nil
func → nil
interface → nil
array → zero value каждого элемента
struct → zero value каждого поля