Yesterday we started talking about Go’s structs, and breezed over a phrase about non-blank field names. Wassat?
Struct types
Go has a concept of a blank identifier. It looks like the underscore character (_
), and is useful in many situations, and we’ll discuss more of them in due time. (It’s also decidedly not useful in some situations where it’s permitted, and I made a video about that a while ago)
For now, we’re only concerned with blank field names. Here’s what one might look like:
type Person struct {
Name string
Age int
_ int64
}
Okay. But why would you ever want that?
Honestly, you probably never do.
But before we dive into the few use cases I know for blank field names, let’s discuss what it actually does:
First off, it does actually affect the struct. The field does exist. And it does take up memory, and it does hold a value:
var x struct {
Name string
}
var y struct {
Name string
_ int64
}
fmt.Println(x, y) // Prints: {} { 0}
fmt.Println(unsafe.Sizeof(x), unsafe.Sizeof(y)) // Prints: 16 24
However, that blank-named field, which definitely does exist, and does take up memory… can never be accessed. You can’t set it to anything other than the default, zero value. The only way to access it is via reflection (which is what fmt.Println
does under the hood to display { 0}
above.)
So when is it useful?
One case where it’s useful is when using CGO, and mapping C structures to Go, when not all of the data in the C structure is useable by Go. By using the blank identifier, one can effectivly “skip” some of the in-memory representation of a struct. This is discussed briefly in this old GitHub issue. Mere mortals need not bother with this frequently.
There are two other places where I’ve seen a blank field name used as well. Although arguably, any unexported field would work for either of these cases:
-
To prevent the use of implicit field names in struct declaration. This requires a short explanation. Normally there are two, equivalent ways of declaring a struct instance:
x := Person{Name: "Bob", Age: 29} y := Person{"Alice", 27}
The latter, shorter, version requires that all field values are present, and in the proper order. By including an unexported field name (including with the blank identifier) in your struct definition, this short hand becomes impossible. Some people feel it is desirable to prevent this short-hand, and may do so with a blank field name, typically of type
struct{}
, which consumes no memory. -
To make structs incomparable. As with the last example, a blank field name is not the only way to do this. Any struct element that is not comparable renders the entire struct incomparable. But this can be done with a blank field name as well. One example from the standard library is in the
net/http
package, where a blank field name of type[0]func()
is used to render the struct incomparable (this works because functions are not comparable).
Do you know of any use for a blank field name in Go? Let me know!
Quotes from The Go Programming Language Specification Version of December 15, 2022