Go import _ ってなんだ

Posted on
go import

import _ "hogehoge"_ は、どういう意味があるんだろうと気になったので調べました。

init()の実行が理由

packageの中身を利用せずに、init()関数が必要な場合に利用するようです。 なので次のように動作を試してみました。

main.go

package main

import (
	"fmt"

	_ "github.com/sourjp/practice/hello"
)

func main() {
	fmt.Println("Hi")
}

hello/hello.go

package hello

import "fmt"

func init() {
	fmt.Println("hello")
}

実行してみるとpackage helloを使いませんが、中に定義されているinit()が実行されていることがわかります。

$ go run main.go
hello
Hi

次に実際のpackageでの使われ方をみていきます。

package imageの場合

package imageでは、Decode()を行うのにRegistration()で拡張子を登録する必要があります。

Values of the Image interface are created either by calling functions such as NewRGBA and NewPaletted, or by calling Decode on an io.Reader containing image data in a format such as GIF, JPEG or PNG. Decoding any particular image format requires the prior registration of a decoder function. Registration is typically automatic as a side effect of initializing that format’s package so that, to decode a PNG image, it suffices to have

import _ "image/png"

package image/pngを覗いてみるとまさにこれですね。

image/png/read.go

func init() {
	image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
}

つまり import _ "image/png" を実行すると、init()image.RegisterFormat() が実行されるので image.Decode() で変換できるということです。

package pgの場合

DB driverを利用する時にも、import _ "github.com/lib/pq" と書きます。この時は何しているんでしょう?

init() を見つけました。これも、sqlのdriverとして登録してくれています。これによって、sql.Open("postgres", ...) が利用できるようなるということですね。

lib/pq/blob/master/conn.go

func init() {
	sql.Register("postgres", &Driver{})
}

まとめ

学んだことを整理します。

  • import _ "hoge" はhoge packageのinit()を実行する
  • 利用するケースは、それをwrapしたpackageがある時(package image, package sqlなど)