Avatar ·

Что означает троеточие `./...` в командах Go?

Привет, коллеги! Я только начал изучать Go и заметил, что в документации и туториалах часто встречается конструкция `./...` в командах, например: ```bash go test ./... go build ./... go vet ./... ``` Я понимаю, что `./` означает текущую директорию, но что делает `...`? Я пытался загуглить, но нашёл только разрозненные объяснения. Мне кажется, что это как-то связано с рекурсивным обходом папок, но не уверен. Например, когда я пишу `go test ./...`, тестируются ли все пакеты во всех вложенных папках? Или только те, которые находятся непосредственно в текущей директории? А если я хочу протестировать только один конкретный пакет, нужно ли убирать троеточие? Ещё я заметил, что в некоторых командах можно использовать `./...` а в некоторых нет. Например, `go run ./...` не работает. Почему так? И есть ли разница между `./...` и просто `./`? Буду очень благодарен за подробное объяснение с примерами, чтобы я наконец разобрался с этой магией. <<>>

Что такое `./...` в Go: полное объяснение

Вы всё правильно поняли — `./...` в командах Go действительно означает рекурсивный обход всех подпапок относительно указанного пути. Это не магия, а специальный паттерн, встроенный в инструментарий Go (go toolchain) для работы с пакетами.

Как это работает

Конструкция `...` (три точки) в Go-командах — это wildcard (шаблон), который означает "все подпакеты рекурсивно". Когда вы пишете:

go test ./...

Go ищет все пакеты (директории с файлами `.go`), начиная с текущей директории (`./`) и рекурсивно заходя во все вложенные папки. Для каждого найденного пакета выполняется команда (в данном случае `go test`).

Конкретные примеры

Предположим, у вас такая структура проекта:

myproject/
├── main.go
├── utils/
│   ├── math.go
│   └── math_test.go
├── api/
│   ├── handler.go
│   └── handler_test.go
└── internal/
    └── db/
        ├── database.go
        └── database_test.go

Команды и их эффект:

  • go test ./... — протестирует пакеты: myproject, myproject/utils, myproject/api, myproject/internal/db.
  • go test ./utils/... — протестирует только myproject/utils (и его подпакеты, если бы они были).
  • go test . — протестирует только корневой пакет myproject (без вложенных).
  • go test ./utils — протестирует только myproject/utils (без рекурсии).

Почему `go run ./...` не работает?

Команда go run предназначена для запуска одного main-пакета (с функцией main()). Она не поддерживает множественные пакеты или рекурсивный обход. Если вам нужно запустить все main-пакеты в проекте, используйте go run ./cmd/... (если структура позволяет) или скрипт оболочки.

Где можно использовать `./...`

Паттерн `...` поддерживается следующими командами:

  • go build
  • go test
  • go vet
  • go list
  • go clean
  • go install

Расширенные возможности

Вы также можете использовать `...` для указания конкретных пакетов внутри модуля:

go test github.com/username/myproject/...

Или для исключения тестов в vendor-папках (если вы используете vendoring):

go test ./... -mod=mod

Практический совет

В современных Go-проектах (с go modules) ./... — это стандартный способ убедиться, что вы не пропустили ни один пакет. Особенно полезно для CI/CD, когда нужно проверить весь проект одной командой.

<<>>

Альтернативный взгляд: как `...` обрабатывается внутри

Стоит добавить, что `./...` — это не просто "магическая строка", а часть паттерна соответствия пакетов в Go. Технически, когда вы пишете go test ./..., Go делает следующее:

  1. Определяет корень модуля (файл go.mod).
  2. Сканирует все директории от указанного пути рекурсивно.
  3. Фильтрует только те директории, которые содержат хотя бы один файл `.go` (это и есть пакеты).
  4. Выполняет команду для каждого такого пакета.

Важный нюанс с vendor

Если ваш проект использует go mod vendor, то ./... не будет заходить в папку vendor/ — Go автоматически её исключает. Это сделано, чтобы не тестировать сторонние зависимости случайно.

Комбинация с другими паттернами

Вы можете комбинировать `...` с отрицанием:

go test ./... -run TestIntegration -count=1

Это запустит только тесты, имя которых содержит "TestIntegration", но во всех пакетах рекурсивно.

Также обратите внимание, что ./... работает только в контексте go-команд. В обычной оболочке (bash, zsh) три точки не имеют специального значения — это именно фича инструментария Go.