25

As I was reading the Go docs I found this:

You can ask the compiler to check that the type T implements the interface I by attempting an assignment:

type T struct{}
var _ I = T{} // Verify that T implements I.

I don't understand what the _ is used for and I've seen it in other assignments but cannot understand what it means. Digging deeper I found that it's called "blank identifier" but I don't understand the use case they put:

_ = x // evaluate x but ignore it

Go idioms still feel a little alien to me so I'm trying to understand why I would want to do something like this.

Julian
  • 8,808
  • 8
  • 51
  • 90
  • The blank identifier `_` can be used to strictly provide the keys in a struct too. See [this](https://developer20.com/golang-tips-and-trics-v/) for reference – Vallie Nov 18 '19 at 12:03
  • Official docs: https://golang.org/doc/faq#guarantee_satisfies_interface – krish7919 Jun 23 '20 at 10:16

5 Answers5

37

_ is a special identifier you can assign anything to but never read from. In the first example you gave:

var _ I = T{}

There is no way to access this variable so it will be optimised out of the resulting program. However, it could cause a compile error if the type T is not assignable to the interface I. So in this case it is being used as a static assertion about a type.

The second case is more common. While it might seem strange to throw away the result of a function call, it can make more sense in functions with multiple returns. Consider a function foo that returns two values but you're only interested in the first? You can use _ to ignore the second:

a, _ = foo()

You could get the same effect by creating another variable to hold the unwanted return value, but this feature means you don't need to worry about picking a unique name for it.

James Henstridge
  • 42,244
  • 6
  • 132
  • 114
  • 2
    AFAIK, The problem in your last statement is not only about picking a unique name for the unwanted variable, but after picking the name you also need to use it. Or else the go compiler throws an error that such as "variable not used". – Suhas Chikkanna Oct 30 '18 at 15:18
  • 1
    @Suhas, this is true. – fuzzybear3965 Jul 09 '19 at 22:38
  • `var _ I = T{}` is actually similar to `var a string = "Shelly"` The "\_" is "a", but is to be ignored. The string is "I", which is a type. The T{} is the value that would be assigned to "\_", just like "Shelly" is assigned to variable "a". In go, we can assign empty struct to a variable. e.g. `type XYZ struct {}` `var emptyXYZ = XYZ{}` `fmt.Print("emptyXYZ:", emptyXYZ)`. `var emptyXYZ = XYZ{}` equals to `var emptyXYZ XYZ = XYZ{}`. If emptyXYZ is not XYZ type, say `var emptyXYZ string = XYZ{}`, there will be an error. And this is what `var _ I = T{}` is checking for :) – shellyyg Sep 21 '22 at 14:21
11

This is common in languages that allow multiple return values. There are situations where you don't actually care about one of the return values.

For example, in Go, it is common to return an error. If for some reason you don't care about that error, you can choose to ignore it:

value, _ := methodThatReturnsValueAndError()

If however, you assign it and don't use it, there is a compiler error:

value, err := methodThatReturnsValueAndError()
// if you don't use "err" .. its an error
Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
4

“There are only two hard things in Computer Science: cache invalidation and naming things”. Tim Bray quoting Phil Karlton

This is about not having to name things.

In Go, when you don't want to use a or foo as an example variable name, you can use _. That's it! They could have written var a I = T{}, the result would have been the same (except that unused variables are an error in Go).

For other uses of the blank identifier, read Effective Go.

Simon
  • 31,675
  • 9
  • 80
  • 92
4

In simple words _ is an ignored value. Go doesn't permit unused local variables and throws a compilation error if you try to do so. So you trick compiler saying "please ignore this value" by placing a _

For example:

// Here range of os.Args returns index, value
for index, arg := range os.Args[1:] {
    fmt.Println(arg)
}

Here Go throws compilation error because you are not using index (un used local variable) at all in the loop. Now you should make index to _ to say compiler to ignore it.

for _, arg := range os.Args[1:] {
    fmt.Println(arg)
}
Naren Yellavula
  • 7,273
  • 2
  • 29
  • 23
3

The Go compiler pretty much disallows variables that are declared but not used. Like so,

for i, myvalue := range myvar {
    total += mvalue
}

The given code will show an error somewhat in this context -> "declared but not used".
Hence, we solve it using the following snippet:

for _, myvalue := range x {
    total += myvalue
}


As for the import part, it's about importing a package solely by its side-effects.
Please refer on this link.

Kent Aguilar
  • 5,048
  • 1
  • 33
  • 20