Table of Contents
Golang Anonymous Struct Definition and Syntax
In our previous article, we gave an overview of Golang structure where we briefly covered Anonymous struct. Now to give you a brief overview, Anonymous struct types are defined without using a name. Go allows you to define anonymous fields: struct fields that have no name of their own, just a type.
A struct without a name is known as anonymous. As a result, we are unable to refer to the structure in other parts of the code. You can define temporary, ephemeral structures using anonymous structures.
Example syntax to create an anonymous structure
is as shown:
variable_name := struct {
// fields
}{field_values}
How to Create Anonymous Struct
The code shown below illustrates how to create an anonymous struct in Go.
package main
import "fmt"
func main() {
// create anon struct
person := struct {
name, nationality string
age int
score float64
}{
name: "Anna_Hurry",
nationality: "England",
age: 21,
score: 9.5,
}
// print anon struct
fmt.Println(person)
}
In the example above, we create an anonymous struct and create an instance of the struct immediately. The above code should print the struct as:
$ go run main.go
{Anna_Hurry England 21 9.5}
How Anonymous struct can be used to compare structs with different types
Structs that are entirely composed of comparable types are comparable; but a struct with slice or map fields are not comparable. Unlike in Python or Ruby, in Go there’s no magic method that can be overridden to redefine equality and make ==
and !=
work for incomparable structs. You can, of course, write your own function that you use to compare structs.
But Go does allow you to perform a type conversion from one struct type to another if the fields of both structs have the same names, order, and types. Let’s see what this means.
Here we have one struct
type firstPerson struct {
name string
age int
}
We can use a type conversion to convert an instance of firstPerson
to secondPerson
, but we can’t use ==
to compare an instance of firstPerson
and an instance of secondPerson
, because they are different types:
type secondPerson struct {
name string
age int
}
We can’t convert an instance of firstPerson to thirdPerson, because the fields are in a different order:
type thirdPerson struct {
age int
name string
}
We can’t convert an instance of firstPerson to fourthPerson because the field names don’t match:
type fourthPerson struct {
firstName string
age int
}
Finally, we can’t convert an instance of firstPerson to fifthPerson because there’s an additional field:
type fifthPerson struct {
name string
age int
favoriteColor string
}
Anonymous structs add a small twist to this: if two struct variables are being compared and at least one of them has a type that’s an anonymous struct, you can compare them without a type conversion if the fields of both structs have the same names, order, and types. You can also assign between named and anonymous struct types if the fields of both structs have the same names, order, and types:
package main
import (
"fmt"
)
type firstPerson struct {
name string
age int
}
func main() {
f := firstPerson{
name: "Bob",
age: 50,
}
var g struct {
name string
age int
}
// compiles -- can use = and == between identical named and anonymous structs
g = f
fmt.Println(f == g)
}
Output:
$ go run main.go
true
Recommended cases to prefer an anonymous struct over a regular struct
The recommended 4 use cases listed here:
- grouped global
- template data
- test tables
- embedded lock
1. Grouped global
We use an anonymous struct to gather all configuration variables into one struct because we do not need to refer this struct anymore.
var config struct {
Username string
Password string
APIKey string
OAuthConfig oauth.Config
}
2. Template data
An anonymous struct can be used as a data template.
data := struct {
Title string
Users []*User
}{
title,
users,
}
3. Test table
The code shown below demonstrate how to use an anonymous struct to create a test table
var testData = []struct {
name string
age int
score float64
}{
{"a A x", 12, 5.5},
{"some_text=some_value", 10, 9.3},
{"a", 12, 8.2},
{"ab", 20, 6.7},
}
var testData = []struct {
name string
age int
score float64
}{
{"a A x", 12, 5.5},
{"some_text=some_value", 10, 9.3},
{"a", 12, 8.2},
{"ab", 20, 6.7},
}
//do some test here
4. Embedded lock
Keeping the mutex close to the data it is intended to protect is excellent practice. It is quite convenient to add the mutex as a field to the struct if it is necessary to prevent concurrent access to its fields. It's known and used to a lesser extent, but it's also handy that you can "truly" embed a mutex in a struct, and you can call Lock() and Unlock() as if they would be part of the struct itself. It looks like this.
var hits struct {
sync.Mutex
n int
}
hits.Lock()
hits.n++
hits.Unlock()
Summary
An anonymous struct is just like a normal struct, but it is defined without a name and therefore cannot be referenced elsewhere in the code. The anonymous struct syntax is simple and we can easily create one anonymous struct. In some cases such as: grouping global variables, create a test data table,… we can use anonymous instead of regular struct.
References
https://go.dev/talks/2012/10things.slide#3
https://pkg.go.dev/sync#Mutex