The underscore in front of an import statement is solely for its side-effects.
An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers. To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name:
import _ "lib/math"
When should we use underscore for import in Golang
Underscore is a special character in Go which acts as null container. Since we are importing a package but not using it, Go compiler will complain about it. To avoid that, we are storing reference of that package into _ and Go compiler will simply ignore it. Aliasing a package with an underscore which seems to do nothing is quite useful sometimes when you want to initialize a package but not use it.
Fixing imported but not used
We can use a blank identifier (_) before the package name that will not be used as following code:
package main
import (
"fmt"
_ "math"
)
func main() {
name := "GoLinuxCloud"
age := 1
fmt.Println("My name is:", name, "and my age is:", age)
}
Fixing declared but not used
In the below code, two variables page
and author
are declared but author
was not used. To avoid compile error, you have to assign the variable to a blank identifier (_
) as the code shown below:
package main
import (
"fmt"
)
func main() {
page := "GolinuCloud"
author := "Anonymous Author"
fmt.Println("Name is:", page)
_ = author
}
Output:
Page is: GolinuCloud
Fixing imported but not used
In the example below, we will import the math package but not use it at all.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println("This is an example of importing packages in Golang!")
}
Output:
$ go run underscore.go
# command-line-arguments
./underscore.go:5:2: imported and not used: "math"
An unused import like math in the previous example should eventually be used or removed: blank assignments identify code as a work in progress.
package main
import (
"fmt"
_ "math"
)
func main() {
fmt.Println("This is an example of importing packages in Golang!")
}
Output:
This is an example of importing packages in Golang!
But sometimes it is useful to import a package only for its side effects, without any explicit use. For example, in the article working with SQLite3 in Golang, we import but not use the go-sqlite3 package:
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
_ "github.com/mattn/go-sqlite3"
: If a package is imported with a blank identifier, the package's init
function is called:
func init() {
if driverName != "" {
sql.Register(driverName, &SQLiteDriver{})
}
}
Once it's registered in this way, sqlite3 can be used with the standard library's sql
interface in your code like in the example:
db, err := sql.Open("sqlite3", ":memory:")
Summary
underscore in front of an import statement means: create package-level variables and execute the init
function of that specific packages. And (if applicable) the hierarchy of package-level variables and init
functions of packages imported by this package.
The only thing a package can do without being called is create package-level variables (public or private) and run its init
function.
References
https://go.dev/doc/effective_go#blank_import
https://go.dev/ref/spec#Import_declarations