---
title: "Переменные и базовые типы"
description: "В первой главе мы печатали готовые значения: \"Аня\", 25, 19.99. В настоящей программе значения приходят откуда-то и меняются по ходу работы: сколько товаров в корзине, сколько…"
canonical: https://graphlms.ru/go-basics/book/variables
course: "Основы Go"
updated: 2026-10-12
lang: ru
publisher: GraphLMS
---

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

> Источник: https://graphlms.ru/go-basics/book/variables — курс «Основы Go», GraphLMS.

## О чём глава

В первой главе мы печатали готовые значения: `"Аня"`, `25`, `19.99`. В настоящей программе значения приходят откуда-то и меняются по ходу работы: сколько товаров в корзине, сколько заплатил покупатель, какая сдача. Чтобы с ними работать, значению дают имя. Это и есть переменная — имя для значения, которое лежит в памяти.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```go play
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` — текст (`"привет"`, `""`). Строки в Go неизменяемы: вы не меняете строку, а создаёте новую. Как строка устроена внутри (байты и кодировка UTF-8), разберём в [главе о коллекциях](/go-basics/book/collections).

Строки склеиваются оператором `+`: `"Привет, " + name` даёт новую строку. Склеить строку с числом так нельзя: `"возраст: " + 25` не соберётся. Для смешанного текста используйте `fmt.Println` или `fmt.Sprintf` (это `Printf`, который не печатает, а возвращает готовую строку).

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

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

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

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

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

```go play
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` берёт строку в кавычки — так сразу видно, что она пустая, а не «пропала».

## Выражения и операторы

Выражение — это запись, которая вычисляет значение: `2 + 3` даёт `5`, а `age >= 18` даёт `true` или `false`.

Для чисел есть привычные `+`, `-`, `*`, `/` и ещё `%` — остаток от деления. Одна ловушка подстерегает почти каждого: деление двух целых чисел даёт целое, дробная часть просто отбрасывается. `17 / 5` равно `3`, а не `3.4`. Чтобы получить дробный результат, оба числа должны быть дробными, например `float64(17) / 5`. Запись `float64(...)` — это преобразование типа, о нём в конце главы.

Сравнения записывают через `==`, `!=`, `<`, `<=`, `>`, `>=`. Один знак `=` присваивает, два `==` сравнивают. Условия соединяют через `&&` («и», нужны оба) и `||` («или», достаточно одного), а `!` меняет `true` на `false` и наоборот.

```go play
package main

import "fmt"

func main() {
	fmt.Println(17/5, 17%5)      // целое деление и остаток
	fmt.Println(float64(17) / 5) // дробное деление

	age := 20
	fmt.Println(age >= 18 && age <= 25) // оба условия верны
	fmt.Println(age < 18 || age > 65)   // ни одно не верно
	fmt.Println(!(age >= 18))
}
```

Вывод:

```text
3 2
3.4
true
false
false
```

Есть короткие формы присваивания: `x += 2` значит `x = x + 2`, `x++` увеличивает `x` на единицу. Аналогично работают `-=`, `*=`, `/=` и `--`. Присваивание сначала вычисляет правую часть, потом записывает результат в переменную слева. Поэтому `x = x + 1` — не уравнение без решений, а команда «возьми старое `x`, прибавь один, положи обратно».

## Константы и iota

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

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

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

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

```go play
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 хочет, чтобы это было ваше осознанное решение, а не случайность.

```go play
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(price)` при `price := 19.99` даёт `19`, а не `20` — дробь *отбрасывается*. А `int(19.99)` с дробной константой не компилируется: константа должна быть точно представима в целевом типе. И преобразование `T(value)` нужно применить к одному из операндов, чтобы их типы совпали.

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

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

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

За три тетради по 40 рублей заплатили 150 рублей. Сохраните количество, цену и оплату в отдельных переменных `int`, вычислите сдачу и напечатайте её. Рядом выведите частное и остаток от деления `17` на `5`. Затем измените оплату на `200` через `=`, пересчитайте сдачу и запустите снова.

### Проверка

Сначала сдача `30`, частное `3`, остаток `2`; после изменения оплаты сдача `80`. Внутри `main` расчёт выглядит так:

```go
count := 3
price := 40
paid := 150
change := paid - count*price
fmt.Println(change, 17/5, 17%5)
paid = 200
change = paid - count*price
fmt.Println(change)
```

`change` хранит уже вычисленное число: изменение `paid` не пересчитывает его автоматически. Для дробного частного можно написать `float64(17) / 5`.

## Что дальше

Теперь у вас есть переменные и типы — материал, на котором строится почти всё остальное. Дальше посмотрим, как из них собирать логику: [условия и циклы](/go-basics/book/control-flow) (`if`, `for`, `switch`), а затем — как упаковывать код в [функции](/go-basics/book/functions).
