Содержание урока · 10 разделов
Операторы 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: кто первый#
Когда в выражении несколько операторов, порядок задаёт приоритет: *, / и % считаются раньше, чем + и -, поэтому 2 + 3 * 4 — это 14, а не 20. Операторы одного уровня вычисляются слева направо — на делении это видно мгновенно: 20 / 2 * 5 равно 50, потому что сначала деление, потом умножение; интуиция «сначала всё умножение» здесь ломается. Сравнения стоят ниже арифметики — a + 1 > b читается как (a + 1) > b, что совпадает с ожиданием. Логические операторы завершают иерархию: ! сильнее &&, а && сильнее || — мы проходили это в уроке про bool и логику.
Скобки меняют любой порядок и ничего не стоят ни во время выполнения, ни в читаемости. Моё правило простое: если в выражении встретились операторы из разных уровней — ставьте скобки, даже когда помните приоритет. Компилятору скобки безразличны, а вот человеку, который через полгода будет править строку salary * 12 / bonus + tax, приятнее видеть, что именно вы имели в виду.
Проверьте себя: порядок слева направо
Что напечатает `fmt.Println(20 / 2 * 5)`?
Выражение (ab) + (cd) и выражение ab + cd дают одинаковый результат, но первое читается мгновенно. Если над строкой кода приходится останавливаться и вспоминать таблицу приоритетов — это повод добавить скобки, а не тест для читателя.
Инкремент в 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.
Что выведет код?
Прочитайте код и выберите, что он выведет:
package main
import "fmt"
func main() {
i := 5
i++
i += 3
fmt.Println(i)
fmt.Println(i > 7 && i < 10)
}Присваивания со сложением: += и друзья#
Каждому арифметическому оператору соответствует составное присваивание: +=, -=, *=, /=, %=. Запись total += 4 означает «прибавь к total четыре и запиши обратно» — то же, что total = total + 4, только короче и без повторения имени переменной. На коротких именах выигрыш скромный, а на длинных — заметный: userProfile.Wallet.Balance -= fee читается лучше, чем та же строка с полным повторением пути слева от равенства.
Отдельная красота — += со строками: log += "готово; " дописывает строку к строке. Присваивание в этом списке — самое «низкое» по приоритету действие: сначала считается вся правая часть, потом результат записывается в левую. И не путайте пары: = — присваивание, := — объявление с выводом типа; после того как переменная объявлена, обновляйте её одинарным равенством или составным оператором, второй раз := для той же переменной в той же области видимости компилятор не пропустит — это из урока про переменные и константы.
Составные присваивания в цепочке
GOpackage 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 без явного преобразования не скомпилируется, о чём подробно говорилось в уроке про числовые типы. Строка с числом тоже не склеится: "версия " + 2 — ошибка о несовпадении типов, даже если на первый взгляд желание понятно. Чтобы получить строку из числа, нужен пакет strconv — например, strconv.Itoa(2), а удобнее всего готовый Sprintf из fmt, где глагол %d сам превращает число в текст — к этому перейдём в уроке про вывод.
Правило одинаковое для всех операторов: типы операндов должны совпадать или быть приводимыми руками. Из-за него выражения в Go получается читать без знания контекста: увидели плюс между значениями — значит, типы совпали, и превращений где-то за кадром не происходит. Строгость здесь экономит время на отладке в десять раз больше, чем отнимает на наборе преобразований.
Соберите программу: итог со скидкой
Соберите программу из строк в правильном порядке: объявить итог, прибавить четыре, удвоить, напечатать. Собранная правильно программа выводит 14 — проверьте себя по этому числу.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Карточки: операторы и выражения
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Три группы операторов: арифметика, сравнения, логика; плюс работает и для строк.
- Приоритет: * / % выше + -; равные приоритеты считаются слева направо.
- Скобки ничего не стоят и делают выражение самодокументированным.
- 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. Компактной записи нет намеренно — каждая строка делает одно видимое действие, и такой код проще читать вслух и править позже.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Изучайте дальше
Следующая ступень учебного пути
Продвинутые возможности Go: от замыканий до рефлексии
Продвинутый курс Go: замыкания, defer, горутины, каналы, контекст, интерфейсы, дженерики, рефлексия, тесты и JSON. 25 уроков с практикой в браузере.
- Писать и читать конкурентный код: go-функции, каналы, select
- Управлять жизненным циклом операций через context
- Проектировать API на интерфейсах
- Использовать дженерики без злоупотребления