What Is a Go Struct and How Do You Write One?
In the Go programming language, a struct (aka “structure”) is a composite data type that makes it possible to group values of different types into a single entity. Structs are handy when you want to group data into a single unity, instead of having to declare separate values.
For example, you could create a struct that collects information on a person like first name, last name and age. You could declare them as individual items, like so:
|
1 2 3 |
var fname string var lname string var age int |
Now, imagine you have to declare a large number of variables. Your code could quickly become a mess and far from efficient to read/understand.
Instead, you could employ a struct to bring those related variables together.
There are a few points you should understand about structs:
- Structs are defined using the type keyword.
- Fields are accessible using the dot operator followed by the field name.
- Structs are initialized by providing values for each field in the order they are defined.
- You can define methods on structs to perform operations on or provide specific behavior to the struct.
- You can compose a struct with other structs.
- You can either pass a struct to a function or assign it to a new variable, both of which create a copy of the struct. To avoid this, you can use pointers to structs.
First, let me show you how to create a struct. Our example will be named Employee and will contain firstName, lastName, age and pay. Remember, we start by defining the struct with the type keyword, which looks like this:
|
1 |
type Employee struct { |
Next, we add our fields, which are firstName (string), lastName (string), age (int) and pay (int). That looks like this:
|
1 2 3 4 5 |
firstName string lastName string age int pay int } |
The struct looks like this:
|
1 2 3 4 5 6 |
type Employee struct { firstName string lastName string age int pay int } |
Now, we’ll create a main function that will specify data for our struct using field names. This is a good way to start because there’s a parallel that’s easy to follow. Let’s define employee1 like this:
|
1 2 3 4 5 6 |
employee1 := Employee{ firstName: "Olivia", lastName: "Nightingale", age: "31", pay: "1000", } |
We could also define the struct without using the field names. This method is faster and cleaner but for those new to Go, it’s less obvious. This method would look like so:
|
1 |
employee1 := Employee{"Olivia", "Nightingale", "31", "1000"} |
What’s important about the above line is the fields must be in the same order as they were declared in the struct. That is the other complication with this type of struct definition. If you were to omit a field or place fields in the wrong order, it could wreak havoc on the app or the output of the app. Because of this, it’s probably best if you stick with the field name definition.
We’ve essentially done the same thing, only one method is quicker.
Let’s roll this struct into an app that will print out the information about our employee. The app looks like this:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package main import ( "fmt" ) type Employee struct { firstName string lastName string age int pay int } func main () { employee1 := Employee { firstName:"Olivia", lastName: "Nightingale", age: 31, pay: 1000, } fmt.Println("Employee 1 details:", employee1) } |
Run the above application and the results will be:
Employee 1 details: {Olivia Nightingale 31 1000}
We could also define a second employee. Let’s do it without using field names. That code looks like this:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package main import ( "fmt" ) type Employee struct { firstName string lastName string age int pay int } func main () { employee1 := Employee { firstName:"Olivia", lastName: "Nightingale", age: 31, pay: 1000, } employee2 := Employee {"Nathan", "Gage", 32, 900} fmt.Println("Employee 1 details:", employee1) fmt.Println("Employee 2 details:", employee2) } |
Run the above application and the results will be:
Employee 1 details: {Olivia Nightingale 31 1000}
Employee 2 details: {Nathan Gage 32 900}
Anonymous structs
You can also declare structs without first creating a new data type. Remember how, in the above struct, we first created the struct with type Employee struct and then defined the struct with employee1 := Employee? With anonymous structs, we can combine those into a single function. Let’s define a third employee in this manner. First, we define employee3 with:
|
1 |
employee3 := struct { |
You should see where this is going. In the next lines, add the fields like so:
|
1 2 3 4 5 |
firstName string lastName string age int pay int } |
So far, this looks like so:
|
1 2 3 4 5 6 |
employee3 := struct { firstName string lastName string age int pay int } |
We then jump right into defining the fields like this:
|
1 2 3 4 5 6 |
} firstName: "Aaron", lastName: "Kennedy", age: 40, pay: 1100, } |
The entire anonymous struct looks like this:
|
1 2 3 4 5 6 7 8 9 10 11 |
employee3 := struct { firstName string lastName string age int pay int }{ firstName: "Aaron", lastName: "Kennedy", age: 40, pay: 1100, } |
The entire application looks like this:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package main import ( "fmt" ) type Employee struct { firstName string lastName string age int pay int } func main () { employee1 := Employee { firstName:"Olivia", lastName: "Nightingale", age: 31, pay: 1000, } employee2 := Employee {"Nathan", "Gage", 32, 900} employee3 := struct { firstName string lastName string age int pay int }{ firstName:"Aaron", lastName: "Kennedy", age: 40, pay: 1100, } fmt.Println("Employee 1 details:", employee1) fmt.Println("Employee 2 details:", employee2) fmt.Println("Employee 3 details:", employee3) } |
As you probably expect, the output of the app looks like this:
Employee 1 details: {Olivia Nightingale 31 1000}
Employee 2 details: {Nathan Gage 32 900}
Employee 3 details: {Aaron Kennedy 40 1100}
Accessing Individual Fields
One final point about structs is that it’s possible to access only a single field. Remember how our output was kind of nondescript? What if we wanted to make it a bit more detailed? We can do that from within the fmt.Println section by accessing individual fields for each printed line. This can be done like so:
|
1 2 3 4 |
fmt.Println("First Name: ", employee1.firstName) fmt.Println("Last Name: ", employee1.lastName) fmt.Println("Age: ", employee1.age) fmt.Println("Pay: ", employee1.pay) |
Now, our output is more structured and looks like this:
First Name: Olivia
Last Name: Nightingale
Age: 31
Pay: 1000
And that, my friends, is how you create a struct in Go. This handy feature can help not only keep your code cleaner and more flexible but also easier to write.