Вариант использования для импорта с пустым идентификатором в golang

В спецификации языка программирования Go указано: "Чтобы импортировать пакет исключительно для его побочных эффектов (инициализация), используйте пустой идентификатор как явное имя пакета".

Например:

import _ "foo/bar"

Мне трудно представить себе пример использования этой конструкции. В принятом ответе на использование инструкции "import" упоминается пример использования драйвера базы данных, который не может быть загружен без необходимости использования какой-либо экспортированной функции этого пакета, но он не учитывает детали для воображения читателя.

Существуют ли примеры реальной жизни (с фрагментами кода и пояснениями), которые иллюстрируют этот вариант использования?

Ответ 1

Я писал масштабирующее устройство. Я хотел, чтобы он мог читать изображения в разных форматах, таких как JPEG, PNG и GIF, и выводить их в формате JPEG.

Поэтому в дополнение к пакетам image и image/jpeg мне также пришлось импортировать image/png и image/gif только для регистрации их соответствующих декодеров.

Если бы я не импортировал их, сканер мог бы только читать изображения JPEG.

package main

import(
  "image"
  "image/jpeg" // I wanted to export the images as JPEG
  _ "image/png"
  _ "image/gif"
)

// ...

Соответствующая документация из пакета image:

Для декодирования любого конкретного формата изображения требуется предварительная регистрация функции декодера. Регистрация обычно является автоматическим в качестве побочного эффекта инициализации этого пакета формата, так что для декодирования изображения PNG достаточно иметь:

import _ "image/png"

Ответ 2

Это происходит из-за функции init

каждый исходный файл может определять свою собственную функцию init niladic для настройки любого состояния. (На самом деле каждый файл может иметь несколько функций init.)

И, наконец, означает, наконец: init вызывается после того, как все объявления переменных в пакете оценили их инициализаторы, и они оцениваются только после того, как все импортированные пакеты были инициализированы.

Вот как работает go-sqlite3, упомянутое в " Что подчеркивает перед выражением импорта в Go ".

func init() {
    sql.Register("sqlite3", &SQLiteDriver{})
}

У вас есть другой пример в разделе " Понимание пакетов Golang ":

В некоторых контекстах нам может понадобиться импортировать пакет только для вызова его метода init, где нам не нужно вызывать другие методы пакета.
Если мы импортируем пакет и не используем идентификатор пакета в программе, Go компилятор покажет ошибку.
В такой ситуации мы можем использовать пустой идентификатор (_) в качестве имени псевдонима пакета, поэтому компилятор игнорирует ошибку, не используя идентификатор пакета, но все равно будет вызывать функцию init.

Ответ 3

Вариант использования - это то, что вы хотите - это только функция init выполняющая некоторую инициализацию (например, регистрируясь, чтобы вам не приходилось их явно называть).

Примером является регистрация некоторых драйверов базы данных:

import (
    "database/sql"
    _ "github.com/ziutek/mymysql/godrv"
)