---
title: "Операторы и выражения"
description: "Операторы в Go: арифметика, приоритеты, инкремент i++, присваивания +=. Почему ++ не выражение и нет тернарного оператора — с запуском кода в браузере."
course: "Go с нуля: базовый синтаксис и конструкции"
url: "https://golangmaster.ru/courses/go-basics/lessons/08-operatory/"
published: "2026-09-19"
updated: "2026-09-28"
minutes: 18
---

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

*Курс «Go с нуля: базовый синтаксис и конструкции», урок 8 из 25. ~18 минут. Обновлено 28.09.2026. Источник: https://golangmaster.ru/courses/go-basics/lessons/08-operatory/*

Арифметика в Go выглядит знакомо: плюс, минус, умножить, разделить. Но на операторах язык показывает характер: инкремент i++ — не выражение и не вернёт значение, у && приоритет выше, чем у ||, а тернарного оператора из C в языке просто нет. Разберём полный набор операторов, правила приоритетов и присваивания со сложением — с кодом, который можно запустить прямо здесь.

### Операторы go: карта языка

Выражение — это комбинация операндов и операторов, которая после вычисления даёт значение: в `2 + 3 * 4` операнды — числа, операторы — плюс и звёздочка, результат — 14. Набор операторов в Go компактный, три группы: арифметика (+ - * / %), сравнения (== != < > <= >=) и логика (&& || !). Плюс унарный минус для чисел: `-a` — это текущее значение a, взятое с обратным знаком.

Два расширения сверх чистой математики. Первое: плюс работает и со строками — склейка `"Go" + "-" + "учим"` даёт "Go-учим". Второе: операторы в Go нельзя перегружать — свои варианты плюса для своих типов определить не выйдет, как в C++ или Kotlin. Комитет Go считает перегрузку источником нечитаемого кода: увидели плюс — знаете точно, что он делает. Это решение в одном ряду с отказом от тернарного оператора, о котором ниже: меньше выразительных средств — меньше способов написать то, что читается иначе, чем работает.

### Арифметические операторы для целых чисел

| Оператор | Пример | Результат | Нюанс |
| --- | --- | --- | --- |
| + | 17 + 5 | 22 | для строк — склейка |
| - | 17 - 5 | 12 | есть унарная форма: -x |
| * | 17 * 5 | 85 | для int легко переполнить |
| / | 17 / 5 | 3 | целочисленное: дробная часть отбрасывается |
| % | 17 % 5 | 2 | работает только с целыми |

### Песочница: арифметика и сравнения

Запустите и сверьте все строки: 22 12 85, затем 3 2 (целочисленное деление из урока про числа), затем три сравнения и унарный минус. Замените a на -17 и посмотрите, как изменится вывод % — остаток в Go повторяет знак делимого.

```go
package main

import "fmt"

func main() {
        a := 17
        b := 5
        fmt.Println(a+b, a-b, a*b)
        fmt.Println(a/b, a%b)
        fmt.Println(a > b, a == b, a != b)
        fmt.Println(-a)
}
```

### Приоритет операторов go: кто первый

Когда в выражении несколько операторов, порядок задаёт приоритет: `*`, `/` и `%` считаются раньше, чем `+` и `-`, поэтому `2 + 3 * 4` — это 14, а не 20. Операторы одного уровня вычисляются слева направо — на делении это видно мгновенно: `20 / 2 * 5` равно 50, потому что сначала деление, потом умножение; интуиция «сначала всё умножение» здесь ломается. Сравнения стоят ниже арифметики — `a + 1 > b` читается как `(a + 1) > b`, что совпадает с ожиданием. Логические операторы завершают иерархию: `!` сильнее `&&`, а `&&` сильнее `||` — мы проходили это в уроке про [bool и логику](/courses/go-basics/lessons/07-bool-i-logika/).

Скобки меняют любой порядок и ничего не стоят ни во время выполнения, ни в читаемости. Моё правило простое: если в выражении встретились операторы из разных уровней — ставьте скобки, даже когда помните приоритет. Компилятору скобки безразличны, а вот человеку, который через полгода будет править строку `salary * 12 / bonus + tax`, приятнее видеть, что именно вы имели в виду.

### Проверьте себя: порядок слева направо

**Вопрос:** Что напечатает `fmt.Println(20 / 2 * 5)`?

- 2
- ✅ 50
- 100
- ошибка компиляции

У / и * одинаковый приоритет, поэтому выражение вычисляется слева направо: сначала 20/2 = 10, затем 10*5 = 50. Вариант 2 получился бы при вычислении справа налево (20/(2*5)), вариант 100 — если бы умножение всегда шло раньше деления.

> **Скобки — бесплатная документация.** Выражение (a*b) + (c*d) и выражение a*b + c*d дают одинаковый результат, но первое читается мгновенно. Если над строкой кода приходится останавливаться и вспоминать таблицу приоритетов — это повод добавить скобки, а не тест для читателя.

### Инкремент в go: инструкция, а не выражение

Здесь Go делает то, чего не делает почти никто из родственников C: `i++` — это не оператор, а отдельная инструкция, и значения она не возвращает. `i := 5; i++; fmt.Println(i)` напечатает 6 — всё честно. Но написать `j := i++` не получится: компилятор ответит ошибкой про неожиданный ++, потому что присваиванию нечего присваивать. По той же причине не существует префиксной формы `++i` — только постфиксная, только как отдельная строка.

Зачем такое ограничение? Из-за него исчезает классика C вроде `a[i++] = i` — код, где одно выражение одновременно читает и двигает счётчик, и порядок вычислений становится головоломкой. В Go инкремент — ровно один шаг: увеличил на единицу и всё. Если нужен другой шаг или «увеличить и использовать», пишите честно: `i += 3` или две строки. К слову, `i++` — это просто сокращение для `i += 1`, а его основная работа происходит в заголовке цикла for — до него дойдём в уроке про [цикл for](/courses/go-basics/lessons/13-cikl-for/).

### Что выведет код?

```go
package main

import "fmt"

func main() {
        i := 5
        i++
        i += 3
        fmt.Println(i)
        fmt.Println(i > 7 && i < 10)
}
```

**Что выведет программа?**

- 8 и true
- ✅ 9 и true
- 9 и false
- ошибка: i++ не работает

i++ увеличивает 5 до 6, затем i += 3 прибавляет три — получается 9. Сравнение 9 > 7 истинно и 9 < 10 истинно, их && тоже истинно. Если вы выбрали «ошибка» — инкремент действительно инструкция, но вполне легальная, ему не нужно быть выражением, чтобы работать.

### Присваивания со сложением: += и друзья

Каждому арифметическому оператору соответствует составное присваивание: `+=`, `-=`, `*=`, `/=`, `%=`. Запись `total += 4` означает «прибавь к total четыре и запиши обратно» — то же, что `total = total + 4`, только короче и без повторения имени переменной. На коротких именах выигрыш скромный, а на длинных — заметный: `userProfile.Wallet.Balance -= fee` читается лучше, чем та же строка с полным повторением пути слева от равенства.

Отдельная красота — `+=` со строками: `log += "готово; "` дописывает строку к строке. Присваивание в этом списке — самое «низкое» по приоритету действие: сначала считается вся правая часть, потом результат записывается в левую. И не путайте пары: `=` — присваивание, `:=` — объявление с выводом типа; после того как переменная объявлена, обновляйте её одинарным равенством или составным оператором, второй раз `:=` для той же переменной в той же области видимости компилятор не пропустит — это из урока про [переменные и константы](/courses/go-basics/lessons/04-peremennye-konstanty/).

### Составные присваивания в цепочке

```go
package main

import "fmt"

func main() {
        balance := 100
        balance -= 30
        balance *= 2
        balance %= 50
        fmt.Println(balance)
        word := "Go"
        word += " пройден"
        fmt.Println(word)
}
```

Цепочка на балансе: 100 - 30 = 70, затем 70 * 2 = 140, затем остаток от деления 140 % 50 = 40. Строковая переменная показывает += в роли дописывания: Go + пробел + слово даёт Go пройден. Каждая строка заменяет более длинную запись с полным повторением имени переменной.

### Чего в go нет: тернарный оператор

В C, JavaScript и Python короткое условие пишется в одну строку: `x > 0 ? "плюс" : "минус"`. В Go такого оператора нет — только развёрнутый if/else из четырёх строк. Спорное решение, к которому я после пары лет на языке пришёл с согласием: тернарник читается хорошо, пока выражения короткие, а дальше превращается в полосу препятствий — вложенные знаки вопроса, скобки ради приоритета, условия внутри условий. Развёрнутый if длиннее, зато читается сверху вниз без прокрутки глазами вправо.

Практический компромисс: когда короткая запись всё-таки нужна, её собирают из двух строк — вычислить в if с начальным присваиванием, сохранить в переменную, присвоить ветку. Идиоматичный вид у этого появляется в уроке про условия: в Go if умеет объявлять переменную в заголовке, и связка «вычислил — проверил» становится почти такой же компактной, как тернарник. Если вам совсем тесно — это честный сигнал, что язык не ваш, и это нормально: выбор инструмента дело личное.

### Типы операндов: что не сложится

Go не складывает операнды разных типов: `int + float64` без явного преобразования не скомпилируется, о чём подробно говорилось в уроке про [числовые типы](/courses/go-basics/lessons/05-tipy-chisel/). Строка с числом тоже не склеится: `"версия " + 2` — ошибка о несовпадении типов, даже если на первый взгляд желание понятно. Чтобы получить строку из числа, нужен пакет strconv — например, strconv.Itoa(2), а удобнее всего готовый Sprintf из fmt, где глагол %d сам превращает число в текст — к этому перейдём в уроке про вывод.

Правило одинаковое для всех операторов: типы операндов должны совпадать или быть приводимыми руками. Из-за него выражения в Go получается читать без знания контекста: увидели плюс между значениями — значит, типы совпали, и превращений где-то за кадром не происходит. Строгость здесь экономит время на отладке в десять раз больше, чем отнимает на наборе преобразований.

### Соберите программу: итог со скидкой

Соберите программу из строк в правильном порядке: объявить итог, прибавить четыре, удвоить, напечатать. Собранная правильно программа выводит 14 — проверьте себя по этому числу.

Правильный порядок строк:

1. `package main`
2. `import "fmt"`
3. `func main() {`
4. `total := 3`
5. `total += 4`
6. `total *= 2`
7. `fmt.Println(total)`
8. `}`

### Карточки: операторы и выражения

- **20 / 2 * 5** — 50. У / и * равный приоритет, вычисление слева направо: (20/2)*5.
- **Почему j := i++ не компилируется?** — i++ — инструкция, а не выражение: она не возвращает значения, присваивать нечего. Префиксной формы ++i в Go нет.
- **Чему эквивалентен i++?** — Записи i += 1. Сам += — составное присваивание: прибавить и записать обратно.
- **Приоритет && и ||** — && связывает крепче ||, а ! сильнее обоих. В смешанных выражениях ставьте скобки.
- **Есть ли в Go тернарный оператор ?:** — Нет. Короткое условие — развёрнутый if/else; в уроке про условия покажем if с объявлением переменной.
- **Можно ли перегрузить оператор?** — Нет, операторы не перегружаются. Плюс работает только так, как определён в языке: числа и склейка строк.

## Коротко: что запомнить

- Три группы операторов: арифметика, сравнения, логика; плюс работает и для строк.
- Приоритет: * / % выше + -; равные приоритеты считаются слева направо.
- Скобки ничего не стоят и делают выражение самодокументированным.
- i++ — инструкция, а не выражение: j := i++ не скомпилируется, префиксной формы нет.
- Составные присваивания += -= *= /= %= сокращают запись, += дописывает строки.
- Тернарного оператора нет: короткое условие пишется if/else.
- Операнды разных типов не смешиваются: int + float64 и строка + число требуют преобразования.

## Домашнее задание

Напишите программу с переменной price := 2400 и discount := 25. Вычислите итоговую цену в два шага: total := price - price/4 (скидка четверть) через составное присваивание, затем выведите total и остаток от деления цены на 100. После этого добавьте строку-лог: log := "итог: " и допишите к ней число через strconv.Itoa(total). Сверьте результат: 2400 - 600 = 1800, остаток 2400 % 100 = 0.

## Вопросы и ответы по уроку

### Почему i++ в Go нельзя использовать внутри выражений?

Авторы языка убрали из инкремента статус выражения, чтобы исчезли двусмысленные записи вроде a[i++] = i, где один оператор одновременно читает индекс и двигает его. В Go ++ работает только как отдельная инструкция: увеличил и всё, порядок вычислений всегда очевиден.

### Есть ли битовые операторы и сдвиги?

Да: & | ^ << >> и маска &^ входят в набор языка с тем же правилом приоритета, что и арифметика. Для старта они не нужны, а пригодятся при работе с флагами и байтовыми протоколами — вернёмся к ним на продвинутом курсе.

### Как записать «увеличить и сразу использовать»?

Двумя строками: сначала i += 3, затем использование i. Компактной записи нет намеренно — каждая строка делает одно видимое действие, и такой код проще читать вслух и править позже.
