The Blank Identifier in Go: A Swiss Army Knife for the Discerning Developer

The Blank Identifier in Go: A Swiss Army Knife for the Discerning Developer

April 6, 2023

Moch Lutfi
Name
Moch Lutfi
Twitter
@kaptenupi

Go is a programming language that is known for its simplicity, efficiency, and ease of use. One of the most interesting features of Go is the blank identifier, also known as the underscore character (_). In this article, we will explore how the blank identifier can be used in multiple assignment, unused imports and variables, import for side effect, and interface checks.

Multiple Assignment

In Go, we can use the blank identifier to ignore values returned by functions during multiple assignment. For example:


a, _, c := foo()

In this example, the second value returned by foo() is ignored by using the blank identifier. This is a common idiom in Go, where functions can return multiple values, but sometimes only some of those values are needed.

Unused Imports and Variables

Go is a statically typed language, which means that variables must be declared before they are used. However, sometimes we may need to import a package or declare a variable, but not actually use it in our code. In such cases, we can use the blank identifier to indicate that the value is not needed.

For example, consider the following code:


import (
"fmt"
_ "net/http/pprof"
)
func main() {
fmt.Println("Hello, world!")
}

In this example, we import the fmt package for printing messages, but we also import the net/http/pprof package for profiling purposes. However, we don't actually use the net/http/pprof package in our code. To indicate that we don't need the package, we use the blank identifier in the import statement.

Similarly, we can use the blank identifier to declare variables that are not used. For example:


func main() {
a, _ := foo()
fmt.Println(a)
}

In this example, the second value returned by foo() is not needed, so we use the blank identifier to indicate that it should be discarded.

Import for Side Effect

In Go, packages can have init functions that are called automatically when the package is imported. Sometimes we may need to import a package only for its init function, and not actually use any of its exported functions or variables. In such cases, we can use the blank identifier to import the package for its side effects.

For example, consider the following code:


import _ "github.com/mattn/go-sqlite3"
func main() {
// Use SQLite...
}

In this example, we import the github.com/mattn/go-sqlite3 package for its init function, which registers the SQLite driver with the database/sql package. We don't actually use any of the exported functions or variables from the package, so we use the blank identifier to indicate that they are not needed.

Interface Checks

In Go, we can use the blank identifier to perform interface checks. For example:


type MyInterface interface {
Foo()
Bar()
}
func foo(a interface{}) {
if _, ok := a.(MyInterface); ok {
fmt.Println("a implements MyInterface")
} else {
fmt.Println("a does not implement MyInterface")
}
}

In this example, we use the blank identifier to ignore the first value returned by the type assertion a.(MyInterface). The second value is a boolean that indicates whether the assertion succeeded or not. By ignoring the first value, we can perform the interface check without having to store the result in a variable.

Conclusion

The blank identifier in Go is a versatile and useful feature that can help us write more expressive and efficient code. By using the blank identifier judiciously and with care, we can make our code more readable and maintainable, while also taking advantage of the unique features of the Go language.