Structs in Go
In this tutorial, we are going to discuss structs in the Go language. A struct (short for “structure”) is a user-defined type that represents a collection of named fields/properties.
Structs are used to group related data together to form a single unit. Any real-world entity that has a set of properties can be represented using a struct.
If you’re coming from an object-oriented background, you can think of a struct as a lightweight class that supports composition but not inheritance.
Structs help in improving the overall code quality by allowing us to create and pass complex data structures across multiple modules.
Imagine passing 10 parameters into a function; you’ll soon run away from code. This is exactly why structs are useful; now, instead of 10 parameters, you simply pass a single struct to that function.
For example, an employee has a firstName, lastName, age, and salary. It makes sense to group these three properties into a single struct named Employee.
Defining a struct type
A struct is declared using two keywords – type and struct. It is wrapped with curly brackets (just like classes in java), which contain fields with a defined type and an identifier(name). You can define a new struct type as follows
type Employee struct {
FirstName string
LastName string
Age int
Salary int
}
The above snippet declares a struct type Employee with fields FirstName, LastName, Age, and Salary. The above Employee struct is called a named struct because it creates a new data type named Employee using employee struct.
The type keyword introduces a new type. It is followed by the name of the type (Employee) and the keyword struct to indicate that we are defining a struct. The struct contains a list of fields inside the curly braces. Each field has a name and a type.
This struct can also be made more compact by declaring fields that belong to the same type in a single line followed by the type name.
In the above struct, FirstName and LastName belong to the same type string and Age and Salary belong to the same type int; hence the struct can be rewritten as
type Employee struct {
FirstName, LastName string
Age, Salary int
}
Initializing a struct
You can initialize a variable of a struct
type using a struct literal as follows
emp := Employee{"Ashok Kumar", "Mariyala", 29, 50000}
Please note that you need to pass the field values in the same order in which they are declared in the struct. Also, you can’t initialize only a subset of fields with the above syntax.
emp := Employee{"Ashok Kumar"} // Compiler Error: too few values in struct initializer
Naming fields while initializing a struct
Go also supports the name: value syntax for initializing a struct (the order of fields is irrelevant when using this syntax).
emp := Employee{FirstName: "Ashok Kumar",Age:29,Salary:50000,LastName:"Mariyala"}
You can separate multiple fields by a new line for better readability (the trailing comma is mandatory in this case)
emp := Employee{
FirstName: "Ashok Kumar",
Age: 29,
Salary: 50000,
LastName: "Mariyala",
}
The name: value syntax allows you to initialize only a subset of fields. All the uninitialized fields are set to their corresponding zero value
emp := Employee{FirstName: "Ashok Kumar",Age:29} // LastName: "", Salary:0
emp := Employee{} // FirstName:"" LastName: "", Salary:0, Age:0
package main
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
Age int
Salary int
}
func main() {
//creating struct specifying field names
emp1 := Employee{
FirstName: "Ashok Kumar",
Age: 29,
Salary: 50000,
LastName: "Mariyala",
}
//creating struct without specifying field names
emp2 := Employee{"Ashok Kumar", "Mariyala", 29, 5000}
fmt.Println("Employee 1 : ", emp1)
fmt.Println("Employee 2 : ", emp2)
}
Output
Employee 1 : {Ashok Kumar Mariyala 29 50000}
Employee 2 : {Ashok Kumar Mariyala 29 5000}
Creating anonymous structs
In the Go language, it is possible to declare structs without creating a new data type. These types of structs are called anonymous structs.
package main
import (
"fmt"
)
func main() {
emp := struct {
FirstName string
LastName string
Age int
Salary int
}{
FirstName: "Ashok Kumar",
Age: 29,
Salary: 50000,
LastName: "Mariyala",
}
fmt.Println("Employee : ", emp)
}
Output
Employee : {Ashok Kumar Mariyala 29 50000}
Accessing fields of a struct
The dot . operator is used to access the individual fields of a struct.
package main
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
Age int
Salary int
}
func main() {
emp := Employee{
FirstName: "Ashok Kumar",
Age: 29,
Salary: 50000,
LastName: "Mariyala",
}
fmt.Println("Employee First Name : ", emp.FirstName)
fmt.Println("Employee Last Name : ", emp.LastName)
fmt.Println("Employee Age : ", emp.Age)
fmt.Println("Employee Salary: ", emp.Salary)
}
Output
Employee First Name : Ashok Kumar
Employee Last Name : Mariyala
Employee Age : 29 Employee
Salary: 50000
Zero value of a struct
When a struct is defined and it is not explicitly initialized with any value, the fields of the struct are assigned their zero values by default.
package main
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
Age int
Salary int
}
func main() {
var emp Employee
fmt.Println("Employee First Name : ", emp.FirstName)
fmt.Println("Employee Last Name : ", emp.LastName)
fmt.Println("Employee Age : ", emp.Age)
fmt.Println("Employee Salary: ", emp.Salary)
}
Output
Employee First Name :
Employee Last Name :
Employee Age : 0
Employee Salary: 0
Pointers to a struct
In Go language, it is possible to create pointers to a struct.
package main
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
Age int
Salary int
}
func main() {
emp := &Employee{
FirstName: "Ashok Kumar",
Age: 29,
Salary: 50000,
LastName: "Mariyala",
}
fmt.Println("Employee First Name : ", (*emp).FirstName)
fmt.Println("Employee Last Name : ", (*emp).LastName)
fmt.Println("Employee Age : ", (*emp).Age)
fmt.Println("Employee Salary: ", (*emp).Salary)
}
Output
Employee First Name : Ashok Kumar
Employee Last Name : Mariyala
Employee Age : 29 Employee
Salary: 50000
The Go language gives us the option to use emp.FirstName instead of the explicit dereference (*emp).FirstName to access the FirstName field.
package main
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
Age int
Salary int
}
func main() {
emp := &Employee{
FirstName: "Ashok Kumar",
Age: 29,
Salary: 50000,
LastName: "Mariyala",
}
fmt.Println("Employee First Name : ", emp.FirstName)
fmt.Println("Employee Last Name : ", emp.LastName)
fmt.Println("Employee Age : ", emp.Age)
fmt.Println("Employee Salary: ", emp.Salary)
}
Output
Employee First Name : Ashok Kumar
Employee Last Name : Mariyala
Employee Age : 29 Employee
Salary: 50000
Anonymous fields
In Go language, it is possible to create structs with fields that contain only a type without the field name. These kinds of fields are called anonymous fields.
The snippet below creates a struct Person which has two anonymous fields string and int
type Person struct {
string
int
}
Even though anonymous fields do not have an explicit name, by default, the name of an anonymous field is the name of its type.
package main
import (
"fmt"
)
type Person struct {
string
int
}
func main() {
person := Person{
string: "Ashok Kumar",
int: 29,
}
fmt.Println(person.string)
fmt.Println(person.int)
}
Output
Ashok Kumar
29
Nested structs
In Go language, a struct may contain a field which in turn is a struct. These kinds of structs are called nested structs.
package main
import (
"fmt"
)
type Address struct {
City string
State string
}
type Person struct {
Name string
Age int
Address Address
}
func main() {
person := Person{
Name: "Ashok Kumar",
Age: 29,
Address: Address{
City: "Hyderabad",
State: "Telangana",
},
}
fmt.Println("Name:", person.Name)
fmt.Println("Age:", person.Age)
fmt.Println("City:", person.Address.City)
fmt.Println("State:", person.Address.State)
}
Output
Name: Ashok Kumar
Age: 29
City: Hyderabad
State: Telangana
Structs Equality
Structs are value types and are comparable if each of their fields is comparable. Two struct variables are considered equal if their corresponding fields are equal.
package main
import (
"fmt"
)
type name struct {
FirstName string
LastName string
}
func main() {
name1 := name{
FirstName: "Ashok Kumar",
LastName: "Mariyala",
}
name2 := name{
FirstName: "Ashok Kumar",
LastName: "Mariyala",
}
if name1 == name2 {
fmt.Println("name1 and name2 are equal")
} else {
fmt.Println("name1 and name2 are not equal")
}
name3 := name{
FirstName: "Ashok Kumar",
LastName: "Mariyala",
}
name4 := name{
FirstName: "Ashok Kumar",
}
if name3 == name4 {
fmt.Println("name3 and name4 are equal")
} else {
fmt.Println("name3 and name4 are not equal")
}
}
Output
name1 and name2 are equal
name3 and name4 are not equal
In the above program, the name struct type contains two string fields. Since strings are comparable, it is possible to compare two struct variables of the type name. Struct variables are not comparable if they contain fields that are not comparable.
Exported and UnExported fields of a struct
Go doesn’t have any public, private, or protected keyword. The only mechanism to control the visibility outside the package is using the capitalized and non-capitalized formats.
- Capitalized Identifiers are exported. The capital letter indicates that this is an exported identifier and is available outside the package.
- Non-capitalized identifiers are not exported. The lowercase indicates that the identifier is not exported and will only be accessed within the same package.
So any struct which starts with a capital letter is exported to other packages. Similarly, any struct field which begins with capital is exported; otherwise, not.
That’s all about the Structs in Go language. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Go language.!!