Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 8 из 25 ~18 мин +50 XP

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

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

Содержание урока · 10 разделов

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

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

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

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

ОператорПримерРезультатНюанс
+17 + 522для строк — склейка
-17 - 512есть унарная форма: -x
*17 * 585для int легко переполнить
/17 / 53целочисленное: дробная часть отбрасывается
%17 % 52работает только с целыми

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

Запустите и сверьте все строки: 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)`?

Инкремент в 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 += "готово; " дописывает строку к строке. Присваивание в этом списке — самое «низкое» по приоритету действие: сначала считается вся правая часть, потом результат записывается в левую. И не путайте пары: = — присваивание, := — объявление с выводом типа; после того как переменная объявлена, обновляйте её одинарным равенством или составным оператором, второй раз := для той же переменной в той же области видимости компилятор не пропустит — это из урока про переменные и константы.

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

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 без явного преобразования не скомпилируется, о чём подробно говорилось в уроке про числовые типы. Строка с числом тоже не склеится: "версия " + 2 — ошибка о несовпадении типов, даже если на первый взгляд желание понятно. Чтобы получить строку из числа, нужен пакет strconv — например, strconv.Itoa(2), а удобнее всего готовый Sprintf из fmt, где глагол %d сам превращает число в текст — к этому перейдём в уроке про вывод.

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

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

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

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

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

Термин

20 / 2 * 5

нажмите, чтобы перевернуть
Определение

50. У / и * равный приоритет, вычисление слева направо: (20/2)*5.

1 / 6

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +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.

Личные заметкиПусто
Хранятся только в вашем браузере (Go Base · Операторы и выражения)

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

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

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

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

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

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

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

Термины урока

Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.

Следующая ступень учебного пути

Go Pro25 уроков~14 чпрактика25 уроков уже доступны

Продвинутые возможности Go: от замыканий до рефлексии

Продвинутый курс Go: замыкания, defer, горутины, каналы, контекст, интерфейсы, дженерики, рефлексия, тесты и JSON. 25 уроков с практикой в браузере.

  • Писать и читать конкурентный код: go-функции, каналы, select
  • Управлять жизненным циклом операций через context
  • Проектировать API на интерфейсах
  • Использовать дженерики без злоупотребления