Язык Go - комментарии
Как в Go устроена документация через комментарии, почему имена пакетов такие короткие и зачем bufio.Reader не называется bufio.BufReader.
Содержание
Если 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 и другие сюрпризы.