Что означает символ подчеркивания перед импортом в Go?
Что такое "пустой идентификатор" в импорте?
Символ подчеркивания (_) в Go называется пустым идентификатором (blank identifier). При использовании в импорте он означает: "импортировать пакет, но не связывать его с каким-либо именем". Это позволяет обойти правило компилятора, запрещающее неиспользуемые импорты.
Как это работает?
В Go у каждого пакета может быть функция init(), которая автоматически выполняется при импорте пакета (до функции main()). Даже если вы не используете экспортируемые имена из пакета, его init() функции всё равно выполняются. Именно это и происходит в вашем примере:
import (
"fmt"
_ "image/png" // init() из image/png регистрирует PNG-декодер
"os"
)
func main() {
// Мы не вызываем функции из image/png напрямую,
// но его init() уже зарегистрировал поддержку PNG
img, _, err := image.Decode(file) // image.Decode использует зарегистрированные декодеры
}
Основные сценарии использования
- Регистрация драйверов/декодеров — как в примере с
image/png. Пакет черезinit()регистрирует себя в родительском пакетеimage. - Подключение датабаз-драйверов — например,
_ "github.com/lib/pq"для PostgreSQL. Драйвер регистрируется вdatabase/sql. - Гарантированный запуск init() — если пакет выполняет важную инициализацию (например, загрузку конфигурации или проверку зависимостей).
- Профилирование и тестирование — подключение пакетов вроде
_ "net/http/pprof"для включения профилировщика.
Когда НЕ стоит использовать
- Если вы реально используете функции из пакета — импортируйте его с именем.
- Если пакет не имеет побочных эффектов (нет
init()) — импорт будет бесполезен. - Для долгоживущих проектов — старайтесь минимизировать такие импорты, так как они усложняют понимание кода.
Как проверить, что делает пакет
Чтобы понять, зачем нужен _ "some/package", посмотрите код его init() функции:
go doc some/package
или откройте исходники. Обычно там одна строка регистрации в родительском пакете.
В вашем случае image/png внутри init() вызывает image.RegisterFormat("png", ...), что позволяет image.Decode() автоматически распознавать PNG-файлы.
Альтернативный взгляд: импорт для тестирования и профилирования
Помимо регистрации драйверов, пустой импорт часто используется в тестовых и отладочных сценариях. Например, для включения HTTP-профилировщика:
import (
_ "net/http/pprof"
)
func main() {
// Теперь доступны /debug/pprof/ эндпоинты
log.Fatal(http.ListenAndServe(":8080", nil))
}
Это добавляет эндпоинты для профилирования без необходимости писать дополнительный код. Аналогично работают пакеты вроде expvar для экспорта метрик.
Практический совет
Если вы видите пустой импорт в чужом коде, всегда проверяйте документацию пакета. Хорошие пакеты явно документируют свои побочные эффекты. Например, в документации database/sql сказано:
"Драйверы должны регистрироваться через init(). Используйте пустой импорт для подключения драйвера."
Также помните, что Go-тулчейн (например, goimports) автоматически удаляет пустые импорты, если они не нужны. Если ваш редактор настроен правильно, он не даст вам оставить бесполезный _ "package".
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги