Перейти к основному содержимому

Синтаксис и пунктуация в Go

Разработчику Архитектору

Названия знаков по-английски и по-русски: Знаки препинания и символы в IT.

Общие принципы

Go использует небольшой набор знаков препинания: синтаксис близок к C, без "магии" вроде ASI в JavaScript. При этом компилятор автоматически вставляет ; в конце строк по лексическим правилам (automatic semicolon insertion), поэтому в обычном коде точку с запятой почти не пишут вручную.


Кавычки и строки

Двойные кавычки "

Строковый литерал — последовательность байт (UTF-8). Экранирование как в C — \n, \t, \".

name := "Alice"
message := "Привет, мир!"
path := "C:\\Users\\dev" // обратный слэш экранируется

Разбор:

  • := создаёт новую переменную с выводом типа из правой части, поэтому name, message и path получают тип string.
  • Литералы в двойных кавычках поддерживают escape-последовательности, поэтому \\ превращается в один символ \ в итоговой строке.
  • Комментарий после // игнорируется компилятором и служит только для объяснения, почему здесь двойной слэш.
  • Все три значения хранятся как неизменяемые строки UTF-8; изменение такого значения всегда создаёт новую строку.

Интерполяции внутри строк нет — для подстановки значений используют fmt.Sprintf или конкатенацию.

fmt.Printf("Hello, %s\n", name)

Разбор:

  • fmt.Printf форматирует строку по шаблону: %s ожидает строковый аргумент, а \n добавляет перевод строки в конце вывода.
  • Параметр name подставляется в позицию %s, поэтому шаблон и список аргументов должны совпадать по типам и количеству.
  • Функция печатает результат в стандартный вывод (stdout), что удобно для консольных программ и отладки.
  • Такой вызов заменяет интерполяцию строк, которая в Go синтаксически отсутствует.

Обратные кавычки `

Raw-строка: переносы строк и обратные слэши сохраняются как есть. Удобно для regex, путей Windows, многострочных шаблонов.

doc := `SELECT *
FROM users
WHERE id = 1`

Разбор:

  • Обратные кавычки создают raw-строку: переносы строк и спецсимволы внутри сохраняются буквально, без экранирования.
  • Переменная doc хранит многострочный SQL-текст в том же виде, как он написан в исходнике.
  • Такой формат удобен для шаблонов, SQL и регулярных выражений, где обычные escape-последовательности перегружают запись.
  • В raw-строке нельзя использовать сам символ обратной кавычки без дополнительных приёмов.

Одинарные кавычки '

Только для литерала rune (int32, кодовая точка Unicode), не для текста.

var letter rune = 'A'
var emoji rune = '🙂' // в исходнике файл должен быть UTF-8

Разбор:

  • rune — это алиас int32, который хранит кодовую точку Unicode, а не строку.
  • Литерал в одинарных кавычках должен содержать один символ (одну кодовую точку), поэтому 'A' и '🙂' корректны.
  • Для emoji в исходнике важна кодировка UTF-8, чтобы компилятор корректно прочитал символ.
  • Такие значения удобно использовать при посимвольной обработке текста и сравнении отдельных символов.

Попытка написать 'hello' — ошибка компиляции: ожидается один символ.


"Умные" апострофы

Символы ' и ' из текстовых редакторов не являются синтаксисом Go. Компилятор выдаст ошибку — в коде только ASCII-кавычки ' и ".

title := "Go Developer's Guide"
quote := "He said: \"Go is simple\""

Разбор:

  • Апостроф внутри строки (Developer's) не требует экранирования, так как строка ограничена двойными кавычками.
  • Внутренние двойные кавычки в quote экранируются через \", иначе строковый литерал завершится раньше времени.
  • Такой пример показывает практическую разницу между обычными символами текста и синтаксическими ограничителями строки.
  • Результирующие значения остаются обычными string и могут дальше передаваться в fmt.Println, JSON и шаблоны.

Точка .

Точка — доступ к полю структуры или методу (в том числе экспортированному, если имя с заглавной буквы):

type Point struct{ X, Y int }
p := Point{X: 5, Y: 10}
fmt.Println(p.X)

Разбор:

  • type Point struct{ X, Y int } объявляет структуру с двумя полями типа int.
  • Литерал Point{X: 5, Y: 10} создаёт экземпляр структуры с явным присваиванием по именам полей.
  • p.X использует точечный доступ к полю структуры; это базовый механизм обращения к данным объекта в Go.
  • fmt.Println выводит значение поля в консоль и автоматически добавляет перевод строки.

Цепочки вызовов:

strings.TrimSpace(strings.ToLower(s))

Разбор:

  • Внутренний вызов strings.ToLower(s) сначала переводит строку s в нижний регистр.
  • Результат этого вызова передаётся во внешний strings.TrimSpace(...), который убирает пробелы по краям.
  • Такой вложенный стиль показывает композицию функций: каждая решает маленькую задачу, итог строится цепочкой.
  • Исходная строка не меняется, потому что строки в Go неизменяемы.

Запятая ,

Разделяет:

  • аргументы функции и параметры в объявлении;
  • элементы среза и литерала структуры;
  • имена в import, const, var (многострочные блоки).
nums := []int{1, 2, 3}
func greet(name string, age int) {}

Разбор:

  • []int{1, 2, 3} создаёт слайс целых чисел с тремя элементами; запятые разделяют элементы литерала.
  • В объявлении func greet(name string, age int) запятая разделяет параметры функции.
  • Тип каждого параметра указывается после имени, что является стандартным синтаксисом Go.
  • Пустое тело {} означает, что функция сейчас только демонстрирует сигнатуру без логики.

В многострочных литералах завершающая запятая после последнего элемента разрешена и часто рекомендуется — так проще добавлять строки в diff:

return []string{
"first",
"second", // trailing comma OK
}

Разбор:

  • Возвращается литерал слайса строк []string{...} прямо из функции без промежуточной переменной.
  • Запятая после последнего элемента в многострочной форме считается корректной и полезной для стабильных diff.
  • Комментарий trailing comma OK подчёркивает, что это осознанная идиома Go-кода.
  • Такой стиль уменьшает шум при добавлении новых элементов в конце списка.

Точка с запятой ;

Вручную ставят в основном в заголовке цикла for:

for i := 0; i < 10; i++ {
fmt.Println(i)
}

Разбор:

  • Это классический for с тремя частями — инициализация i := 0, условие i < 10, шаг i++.
  • На каждой итерации fmt.Println(i) печатает текущее значение счётчика.
  • Цикл завершится, когда условие станет ложным (i достигнет 10).
  • В Go это одна из форм единственного циклического оператора for.

В остальных строках компилятор вставляет ; сам. Явные ; в конце строк допустимы, но не приняты в идиоматичном стиле.


Скобки

СимволНазначение
()Вызов функции, группировка, условие if/for
{}Тело функции, блок; обязательны даже для одной строки
[]Срез, массив, индекс
if x > 0 {
fmt.Println("positive")
}

Разбор:

  • Условие x > 0 должно иметь тип bool; неявные преобразования к булеву типу в Go отсутствуют.
  • Фигурные скобки обязательны даже для одной команды в теле if.
  • При истинном условии выполняется вызов fmt.Println("positive").
  • Такой явный блочный синтаксис снижает риск ошибок при расширении ветки.

Отсутствие фигурных скобок у if — синтаксическая ошибка (в отличие от C или JavaScript).


Подчёркивание _

  • _ как имя — значение отбрасывается (импорт только ради побочного эффекта, игнор возвращаемого значения).
  • В числах 1_000_000 — разделитель для читаемости (с Go 1.13).
  • Не экспортируемые идентификаторы начинаются со строчной буквы; подчёркивание в начале имени не делает поле "приватным" — приватность определяется регистром первой буквы пакета.
_, err := fmt.Println("ok")
const billion = 1_000_000_000

Разбор:

  • _ — пустой идентификатор: он принимает значение и сразу его отбрасывает, чтобы не хранить ненужный результат.
  • err := ... сохраняет только ошибку из множественного возврата fmt.Println.
  • 1_000_000_000 использует подчёркивания как визуальные разделители разрядов без изменения численного значения.
  • Такой стиль повышает читаемость больших чисел и помогает избегать ошибок при ручном вводе.

Двоеточие :

В объявлениях с коротким синтаксисом:

name := "Go" // новая переменная
for i, v := range slice {}
switch x := v.(type) {}

Разбор:

  • name := "Go" создаёт новую локальную переменную с типом string.
  • for i, v := range slice одновременно объявляет индекс i и копию элемента v при проходе по слайсу.
  • switch x := v.(type) демонстрирует type-switch: x получает конкретный динамический тип из интерфейсного значения.
  • Во всех трёх конструкциях := совмещает объявление переменных и начальную инициализацию.

Типичные ошибки

  1. Строка в одинарных кавычках — нужны двойные или raw.
  2. Забыть {} у if — в Go блок всегда в фигурных скобках.
  3. Смешать rune и string при сравнении — явное преобразование string(r).
  4. Неиспользуемый импорт или переменная — компилятор не соберёт проект (в отличие от многих языков).
var r rune = 'Ж'
if string(r) == "Ж" {
fmt.Println("совпало")
}

Разбор:

  • r хранит одну кодовую точку Unicode, а не строку, поэтому прямое сравнение r == "Ж" было бы ошибкой типов.
  • Преобразование string(r) создаёт строку из одного символа и делает сравнение с "Ж" корректным.
  • Условие в if возвращает bool, и при совпадении выполняется печать в консоль.
  • Это типичный реальный паттерн при обработке текста, когда в коде смешиваются rune и string.

Связанные материалы