GraphLMS

Основы
Начать
Глава 02 · Основы~12 мин чтения

Переменные и базовые типы

О чём глава

Переменная — это имя для значения, которое лежит в памяти. В Go у каждой переменной есть тип, и он известен ещё до запуска программы: компилятор знает, что в age лежит целое число, а в name — строка. Благодаря этому многие ошибки ловятся при сборке, а не у пользователя.

В этой главе разберёмся, как объявлять переменные двумя способами (var и :=), какие есть базовые типы (int, float64, bool, string), что такое нулевые значения, как объявлять константы с iota и почему Go заставляет преобразовывать типы вручную.

Объявление через var

Самый явный способ — ключевое слово var, имя, тип и (по желанию) начальное значение:

var age int = 30
var name string = "Аня"
var active bool = true

Если вы задаёте начальное значение, тип можно не писать — компилятор сам его выведет из правой части. Это называется выводом типа (type inference):

var age = 30        // int
var price = 19.99   // float64
var name = "Аня"    // string

Тут важная интуиция: тип никуда не делся, просто его за вас угадал компилятор. age по-прежнему строго int, и положить туда строку уже нельзя.

Можно объявить переменную без значения — тогда она получит нулевое значение своего типа (об этом ниже):

var count int      // станет 0
var greeting string // станет ""

Короткое объявление :=

Внутри функций чаще всего пишут ещё короче — через :=. Это объявление и присваивание одновременно, тип всегда выводится автоматически:

age := 30
name := "Аня"
active := true

Запись := работает только внутри функций. На верхнем уровне пакета (вне функций) используйте var. И ещё: := именно создаёт новую переменную. Если переменная уже есть и вы хотите просто поменять её значение — используйте обычное =:

x := 10  // создали
x = 20   // изменили

Соберём всё вместе и посмотрим на типы. Функция fmt.Printf с глаголом %T печатает тип значения, а %v — само значение:

package main
 
import "fmt"
 
func main() {
	var age = 30
	price := 19.99
	name := "Аня"
	active := true
 
	fmt.Printf("age=%v (%T)\n", age, age)
	fmt.Printf("price=%v (%T)\n", price, price)
	fmt.Printf("name=%v (%T)\n", name, name)
	fmt.Printf("active=%v (%T)\n", active, active)
}

Вывод:

age=30 (int)
price=19.99 (float64)
name=Аня (string)
active=true (bool)

Базовые типы

Для старта вам хватит четырёх типов:

  • int — целые числа (-2, 0, 42). Это «число по умолчанию»: если вы пишете x := 7, получится int.
  • float64 — числа с дробной частью (3.14, -0.5, 19.99). Тип по умолчанию для дробей.
  • bool — логическое значение: только true или false.
  • string — текст в кодировке UTF-8 ("привет", ""). Строки в Go неизменяемы: вы не меняете строку, а создаёте новую.

Есть и другие числовые типы (int8, int64, uint, float32 и прочие) — они нужны, когда важен размер или знак. Пока достаточно знать, что они существуют; в обычном коде по умолчанию берут int и float64.

Нулевые значения

В Go не бывает «мусора» в неинициализированной переменной. Если вы объявили переменную, но не дали ей значения, она получает нулевое значение (zero value) своего типа — предсказуемое и безопасное:

  • у чисел (int, float64) это 0;
  • у boolfalse;
  • у string — пустая строка "".

Это удобно: можно объявить переменную заранее и не бояться, что в ней окажется что-то случайное.

package main
 
import "fmt"
 
func main() {
	var n int
	var f float64
	var b bool
	var s string
 
	fmt.Printf("int:    %v\n", n)
	fmt.Printf("float:  %v\n", f)
	fmt.Printf("bool:   %v\n", b)
	fmt.Printf("string: %q\n", s)
}

Вывод:

int:    0
float:  0
bool:   false
string: ""

Здесь %q берёт строку в кавычки — так сразу видно, что она пустая, а не «пропала».

Константы и iota

Константа — это значение, которое известно на этапе компиляции и не может измениться во время работы программы. Объявляется через const:

const Pi = 3.14159
const AppName = "MyApp"
const MaxRetries = 3

Попытка присвоить константе новое значение — ошибка компиляции, программа просто не соберётся. Это страховка: имена вроде MaxRetries не должны меняться по ходу дела.

Часто нужно перечисление — набор связанных целых констант (дни недели, состояния, уровни). Чтобы не писать 0, 1, 2, 3 руками, в Go есть iota. Внутри блока const iota начинается с 0 и увеличивается на единицу с каждой следующей строкой:

package main
 
import "fmt"
 
const (
	Sunday = iota // 0
	Monday        // 1
	Tuesday       // 2
	Wednesday     // 3
)
 
func main() {
	fmt.Println(Sunday, Monday, Tuesday, Wednesday)
}

Вывод:

0 1 2 3

Обратите внимание: значение = iota мы написали только в первой строке, а дальше Go повторяет эту же формулу для каждой константы — поэтому числа сами растут. Так из iota получается аккуратная нумерация без ручного счёта.

Преобразование типов

А вот это место часто удивляет новичков. В Go нет неявного преобразования между числовыми типами. Нельзя просто сложить int и float64 — компилятор откажется, даже если математически всё «понятно». Преобразование всегда пишется явно: T(value).

Зачем так строго? Чтобы вы сами решали, что делать с потерей точности. Превратить float64 в int — значит отбросить дробную часть, и Go хочет, чтобы это было ваше осознанное решение, а не случайность.

package main
 
import "fmt"
 
func main() {
	count := 3       // int
	price := 19.99   // float64
 
	// count * price — ошибка: разные типы.
	// Приводим count к float64 явно:
	total := float64(count) * price
	fmt.Printf("total = %.2f\n", total)
 
	// Обратно: float64 -> int отбрасывает дробь (не округляет!)
	whole := int(price)
	fmt.Printf("whole = %d\n", whole)
}

Вывод:

total = 59.97
whole = 19

Запомните два момента: int(19.99) даёт 19, а не 20 — дробь именно отбрасывается, округления не происходит. И преобразование T(value) нужно применить к одному из операндов, чтобы их типы совпали.

Частые ошибки

  • := вне функции. Короткое объявление работает только внутри функций. На уровне пакета пишите var.
  • := для уже существующей переменной. := создаёт новую переменную. Чтобы изменить имеющуюся, используйте =. Повторный := в той же области видимости — ошибка «no new variables on left side».
  • Неиспользуемая переменная. Go считает объявленную, но ни разу не использованную локальную переменную ошибкой компиляции. Это не придирка, а защита от опечаток. Если переменная пока не нужна — удалите её или используйте.
  • Сложение int и float64 напрямую. Так нельзя — преобразуйте один из операндов явно: float64(count) * price.

Что дальше

Теперь у вас есть переменные и типы — материал, на котором строится почти всё остальное. Дальше посмотрим, как из них собирать логику: условия и циклы (if, for, switch), а затем — как упаковывать код в функции.