We have already seen Arrays, Slices, and maps. They all have a common limitation: they can store or process only one data type. But sometimes, we need to group various values ( an int, float, or a string ). And Go provides us with a way to do just that by using struct. Golang struct ( short for “structure” ) is a user-defined type that represents a collection of data fields. We can group different items into a single entity using struct.
In this post, we are going to learn about the Golang structs in detail.
- How to create a Golang struct
- Accessing and modifying a struct
- Accessing struct fields through pointers
- Struct literals
- How to export structs
Well, there are other topics regarding structs that we have covered in separate posts.
- Golang Nested Structs ( Nested structs in Golang )
- Anonymous struct and fields in Golang
- Golang Embedded structs and Promoted fields
How to create a Golang struct
We can declare a struct by using the struct keyword, followed by the curly braces. And within the braces, we can define one or more fields the struct would contain. Each field definition consists of the field name, followed by its data type.
Syntax of declaring a struct
struct {
field1 field1_DataType
field2 field2_DataType
}
We can create our user-defined type using struct and then make the variables of that type. Below is the syntax for declaring a user-defined type.
type type_name struct {
field1 field1_DataType
field2 field2_DataType
}
So, if we want to create our user-defined type “Person”, then we can do it like this –
type Person struct {
firstName string
lastName string
age int
height float64
}
We can also place the fields of the same type in a single line.
type Person struct {
firstName, lastName string
age int
height float64
}
Now, we can also create variables of the type Person.
var person1 Person
Accessing and modifying a struct using the dot operator
We have created our struct, but how do we update its fields or access them in the Go language? This is where the dot operator( . ) will come to the rescue. Dot operator can be used for assigning values, updating, and retrieving them.
package main
import "fmt"
type Person struct {
firstName string
lastName string
age int
height float64
}
func main() {
var person1 Person
// assiging the values to the fields
// of struct using dot operator
person1.firstName = "codekru"
person1.lastName = "website"
person1.age = 22
person1.height = 167.12
fmt.Println("Person's age:", person1.age) // retrieving "age" using dot operator(.)
person1.age = 30 // Updating the "age" value using "dot" operator(.)
fmt.Println("Updated Person's age:", person1.age) // again retrieving "age" using dot operator(.)
}
Output –
Person's age: 22
Updated Person's age: 30
Accessing struct fields through pointers
How do we usually get the values stored at the pointer’s location? We use something like this.
func main() {
var var1 int = 8
var pointerToVar1 *int = &var1
fmt.Println("value at var1:", *pointerToVar1)
}
Then you might think we would use * with the struct as well, but that won’t work.
package main
import "fmt"
type Person struct {
firstName string
lastName string
age int
height float64
}
func main() {
var person1 Person
person1.age = 30
var pointerToPerson *Person = &person1
fmt.Println("Person's age:", *pointerToPerson.age)
}
invalid indirect of pointerToPerson.age (type int)
If we are writing *pointerToPerson.age, then Go thinks that age contains a pointer, but it doesn’t. To rectify this, we have to wrap the pointer within the parenthesis, and all would work fine.
package main
import "fmt"
type Person struct {
firstName string
lastName string
age int
height float64
}
func main() {
var person1 Person
person1.age = 30
var pointerToPerson *Person = &person1
fmt.Println("Person's age:", (*pointerToPerson).age)
}
Output –
Person's age: 30
Writing this syntax will become tedious at some point, so the dot operator (.) provides a very convenient way of accessing the fields of a struct through pointers.
Struct literals
Go provides us with the struct literals, which are similar to array literals for arrays, slice literals for slices, and map literals to work with maps. Go offers struct literal to let us create a struct and set its fields simultaneously and saves us from assigning the values one by one using the dot operator.
The syntax of a struct literal is almost similar to a map literal.
- A struct literal starts with a struct type.
- Then key/value pairs will be enclosed within the curly braces
- For each pair, the key and the value will be separated by a colon ( : )
- And multiple key-value pairs will be separated by the comma ( , )
person2 := Person{firstName: "Codekru", age: 22, height: 167.12, lastName: "website"}
package main
import "fmt"
type Person struct {
firstName string
lastName string
age int
height float64
}
func main() {
person1 := Person{firstName: "Codekru", age: 22, height: 167.12, lastName: "website"}
fmt.Println("Person's age:", person1.age)
}
Output –
Person's age: 22
Here, you might have noticed that the order of the field is different than what was specified during the declaration of the struct. We can specify the fields in any order while creating or defining structs using fields. Here, we have used the shorthand declaration to create a struct.
Without specifying fields
We can also set the fields of a struct without specifying the fields we are setting it for.
package main
import "fmt"
type Person struct {
firstName string
lastName string
age int
height float64
}
func main() {
person1 := Person{"Codekru", "Website", 22, 167.12}
fmt.Println("Person's age:", person1.age)
}
Output –
Person Details: {Codekru Website 22 167.12}
Here, the order of the fields should be the same as specified in the struct declaration.
How to export structs
We have to start the struct type name with a capital letter to export it outside of the package it’s defined in, and the same would also be the case for the struct fields. If we start the struct or its fields with the lowercase letters, then we won’t be able to use them outside of the package they are defined in.
Let’s make a package containing only the struct type and then use it elsewhere in other packages.
- Create a new directory named “structs” inside the src folder of your workspace. For us, the src folder location is “C:\Program Files\Go\src”
- Create another directory called “codekru” inside the “structs“
- Now, create a codekru.go file that will contain the Person struct
|__src
|
|___structs
|
|___codekru
|
|___codekru.go
codekru.go file
package codekru
type Person struct {
FirstName string // exported field
lastName string // unexported field
Age int //exported field
height float64 // unexported field
}
To export the above struct, let’s create another file named “main.go” anywhere on the machine. Now, the Person struct should be prefixed with “codekru“, just like what we do with the fmt package and its functions ( fmt.Println() ).
main.go file
package main
import (
"fmt"
"structs/codekru"
)
func main() {
var person1 codekru.Person
person1.Age = 30
fmt.Println("Person's age:", person1.Age)
}
Output –
Person's age: 30
Let’s try to access the unexported fields of the struct.
package main
import (
"fmt"
"structs/codekru"
)
func main() {
var person1 codekru.Person
person1.lastName = "website"
fmt.Println("Person's lastname:", person1.lastName)
}
Output –
.\main.go:11:9: person1.lastNamee undefined (type codekru.Person has no field or method lastName)
.\main.go:13:43: person1.lastName undefined (cannot refer to unexported field or method lastName)
We hope that you have liked the article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at admin@codekru.com.