· 8 мин 👁 1.2k Начинающий

Язык Go - комментарии

Как в Go устроена документация через комментарии, почему имена пакетов такие короткие и зачем bufio.Reader не называется bufio.BufReader.

комментарииgodocстиль
Содержание

Если gofmt решил вопрос форматирования, то Go решил ещё два вечных вопроса — как комментировать код и как называть вещи. Не идеально, но достаточно конкретно, чтобы не спорить.

Два вида комментариев

Go поддерживает оба стиля из C-семейства:

// однострочный комментарий — норма в Go

/* блочный комментарий — для пакетов
   или чтобы закомментировать кусок кода */

Однострочные // используются повсеместно. Блочные /* */ — в основном для комментария пакета в начале файла или чтобы быстро выключить большой кусок кода во время отладки.

Doc comments: документация прямо в коде

Вот где начинается магия. Комментарий, написанный непосредственно перед объявлением верхнего уровня (функция, тип, переменная, константа) — это не просто комментарий. Это документация.

// Server представляет HTTP-сервер с поддержкой таймаутов.
// Нулевое значение готово к использованию с настройками по умолчанию.
type Server struct {
    Host    string
    Port    int
    Timeout time.Duration
}

// ListenAndServe запускает сервер на указанном адресе.
// Блокирует выполнение до ошибки или вызова Shutdown.
func (s *Server) ListenAndServe() error {
    // ...
}

Запустите go doc — эти комментарии станут автоматической документацией. Никакого отдельного markdown, никаких wiki.

Ключевое правило: между doc comment и объявлением не должно быть пустых строк. Одна пустая строка — и комментарий больше не является doc comment.

Как начинать doc comment

По конвенции, doc comment начинается с имени того, что документирует:

// Fprintf форматирует строку и записывает в w.
// Возвращает количество записанных байт и ошибку.
func Fprintf(w io.Writer, format string, a ...any) (n int, err error)

Это не случайно — так комментарии хорошо читаются в grep и godoc, когда видишь только одну строку из контекста.

Именование: коротко, но не в ущерб смыслу

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

type server struct { ... }  // не видна снаружи пакета
type Server struct { ... }  // экспортируется — видна всем

Поэтому именование — это не просто эстетика.

Имена пакетов

Пакеты в Go называют маленькими буквами, одним словом, без подчёркиваний и camelCase:

import "bytes"       // хорошо
import "encoding/base64"  // хорошо — имя пакета будет base64
// import "myUtils"  // плохо
// import "my_utils" // плохо

Почему так коротко? Потому что имя пакета будет использоваться каждый раз, когда вы обращаетесь к его содержимому. bytes.Buffer — удобно. byteUtils.Buffer — уже раздражает.

Пакет и его содержимое — одна команда

Вот хитрость, которую стоит усвоить: имя пакета — часть имени того, что вы экспортируете.

Тип Reader в пакете bufio снаружи выглядит как bufio.Reader. Поэтому называть его BufReader было бы избыточно — получилось бы bufio.BufReader. Некрасиво и многословно.

// пакет bufio
type Reader struct { ... }   // снаружи: bufio.Reader ✓
// type BufReader struct {}  // было бы: bufio.BufReader ✗

Ещё пример — пакет ring. В нём один экспортируемый тип Ring и конструктор. Конструктор называется не NewRing, а просто New:

// пакет ring
func New(n int) *Ring { ... }  // снаружи: ring.New(n) ✓
// func NewRing(...) — было бы ring.NewRing(...) — масло масляное

И ещё один — once.Do(setup). Не once.DoOrWaitUntilDone(setup). Читается как английское предложение и не требует пояснений.

Длинное имя ≠ понятное имя

Это важный принцип, который Go продвигает довольно настойчиво: длинные имена не делают код читабельнее автоматически. Хороший doc comment часто ценнее, чем попытка вместить всю суть в имя функции.

// плохо — имя перегружено
func ParseAndValidateUserInputWithFallback(s string) (User, error)

// лучше — коротко + doc comment объяснит детали
// ParseUser разбирает строку в User. При ошибке возвращает DefaultUser.
func ParseUser(s string) (User, error)

Итоги

  • Doc comments — комментарии прямо перед объявлением, без пустой строки между ними. Начинаются с имени того, что документируют
  • Блочные /* */ — для пакетных комментариев и временного отключения кода
  • Имена пакетов: строчные, одно слово, без подчёркиваний
  • Имя пакета — часть публичного имени: bufio.Reader, а не bufio.BufReader
  • Длинное имя не равно понятное имя — хороший комментарий лучше

Следующий шаг: Управляющие конструкции в Go — if без скобок, switch без break и другие сюрпризы.