BackendBit

К глоссарию

Литерал

Другие названия
literal

Литерал – запись значения прямо в исходном коде: 42, "Привет", []int{1, 2, 3}. К переменной и именованной константе обращаются по имени, а литерал и есть само значение – оно видно в тексте программы.

Литералы в Go

Спецификация Go делит литералы на три вида: базовые, составные и функциональные.

Базовые литералы

Базовые – это литералы чисел, символов и строк. Их пять:

  • целые: 42, 0x2A, 0b101010, 0o52, 1_000_000;
  • с плавающей точкой: 3.14, 1e9;
  • мнимые: 2i, 1.5i – мнимая часть комплексного числа;
  • руны: 'я', '\n';
  • строковые: "Привет\n" и `C:\dir`.

true, false и nil выглядят как литералы, но в Go это предобъявленные идентификаторы, такие же, как int или len.

Литералы и константы

В Go базовый литерал – константа, причём без типа: 1 – это не int и не float64, а просто число. Такую константу называют нетипизированной. Тип она получает там, где её используют: в var f float64 = 1 единица становится float64, а в var b byte = 1 – byte:

var f float64 = 1
var b byte = 1

fmt.Printf("%T %T\n", f, b)
go
float64 uint8

uint8 – это byte: %T печатает настоящее имя типа, а не алиас.

У переменной, в отличие от литерала, такой гибкости нет: если i объявлена как int, то var f float64 = i не скомпилируется.

Когда тип взять неоткуда, например в x := 42, литерал получает тип по умолчанию. Он свой у каждого вида литерала:

fmt.Printf("%T\n", 42)
fmt.Printf("%T\n", 3.14)
fmt.Printf("%T\n", 2i)
fmt.Printf("%T\n", 'я')
fmt.Printf("%T\n", "Привет")
go
int
float64
complex128
int32
string

У рунного литерала тип по умолчанию rune, но это алиас int32, а %T, как и выше, печатает настоящее имя типа.

Литералу можно дать имя: const answer = 42. Теперь answer – та же нетипизированная константа, что и 42.

Константами в Go бывают только булевы значения, числа и строки, поэтому составной литерал константой не станет: const nums = []int{1, 2, 3} не скомпилируется.

Составные литералы

Составной литерал создаёт значение структуры, массива, слайса или мапы: сначала тип, затем элементы в фигурных скобках.

dog := Dog{Name: "Шарик"}
arr := [3]int{1, 2, 3}
slice := []string{"a", "b"}
ages := map[string]int{"Шарик": 3, "Мурка": 5}

fmt.Println(dog, arr, slice, ages)
go
{Шарик} [1 2 3] [a b] map[Мурка:5 Шарик:3]

Базовый литерал – константа, его значение известно уже при компиляции. Составной литерал вычисляется во время работы программы, поэтому его элементами могут быть любые выражения: Dog{Name: name}, []int{x, f()}. И каждое вычисление создаёт новое значение: newDog ниже дважды выполняет один и тот же литерал &Dog{Name: name} и возвращает указатели на две разные структуры:

a := newDog("Шарик")
b := newDog("Шарик")
a.Name = "Бобик"

fmt.Println(a == b, a.Name, b.Name)
go
false Бобик Шарик

Функциональные литералы

Функциональный литерал – анонимная функция: func(a, b int) int { return a + b }. Его можно присвоить переменной, передать аргументом или сразу вызвать. Кроме того, это замыкание: он видит переменные окружающей функции и может их менять.

count := 0
inc := func() {
	count++
}

inc()
inc()
fmt.Println(count)
go
2

inc меняет count окружающей функции, а не свою копию, поэтому после двух вызовов count равен 2.

Подробнее о строковых литералах – в статье Строки в Go, о слайс литералах – в статье Слайсы в Go.