Go Structures
A structure, usually called a struct in Go, is a user-defined type that groups related fields under one name. Each field can have a different datatype. For example, a student struct can contain a name as a string, a roll number as an integer, and an active status as a Boolean value.
Go structs are useful for representing records and application data such as users, products, configuration values, API responses, and database rows. Unlike classes in some object-oriented languages, a Go struct does not define inheritance. Behavior can instead be associated with a struct by declaring methods with receiver parameters.
In this tutorial, you will learn how to define a struct, declare and initialize struct variables, access fields, work with pointers, attach methods, use struct tags, embed structs, and distinguish structs from interfaces.
Declare a Struct Type in Go
To declare a structure in Go, use the keywords type and struct. Field declarations are written inside braces. Go code normally uses a descriptive type name in PascalCase when the type must be exported from its package.
The syntax to declare a structure is
type struct_name struct {
member definition;
member definition;
...
member definition;
}
The following is an example, to declare student structure datatype with properties: name and rollNumber.
example.go
package main
type student struct {
name string
rollNumber int
}
func main() {
}
The field names in this example begin with lowercase letters, so they are available only within the same package. A field beginning with an uppercase letter, such as Name, is exported and can be accessed from another package.
Declare Variables of a Go Struct Type
After defining a struct type, you can declare variables of that type with the var keyword. A declared struct variable is initialized with the zero value of each field. For the student type below, name initially contains an empty string and rollNumber initially contains 0.
example.go
package main
type student struct {
name string
rollNumber int
}
func main() {
// declare variables of Student type
var student1 student
var student2 student
}
Initialize Go Struct Variables with Struct Literals
A struct literal creates a struct value and optionally supplies values for its fields. You can initialize a struct when declaring the variable or assign a struct value later.
example.go
package main
type student struct {
name string
rollNumber int
}
func main() {
// intialize during declaration
var student1 = student{name:"A", rollNumber:14}
var student2 student
// intialize explicitly
student2 = student{name:"B", rollNumber:13}
}
Using field names in a struct literal is generally clearer and safer because the values do not depend on the order of fields in the type definition. You can also omit fields that should retain their zero values.
package main
import "fmt"
type Student struct {
Name string
RollNumber int
Active bool
}
func main() {
student := Student{
Name: "Maya",
RollNumber: 21,
}
fmt.Println(student)
}
Output
{Maya 21 false}
The Active field was not included in the literal, so it received the zero value false.
Access and Update Go Struct Fields
To access members of a structure, use dot . operator. You can access a specific member by writing structure variable, followed by dot and then the member variable name.
In the following example, we have used dot operator to set the value of member of the structure variable and also to get the value of a member.
example.go
package main
import "fmt"
type student struct {
name string
rollNumber int
}
func main() {
var student1 = student{name:"Anu", rollNumber:14}
// get the member value
fmt.Printf("student1 details\n--------------\n")
fmt.Printf("Name : %s\n", student1.name)
fmt.Printf("Rollnumber : %d\n", student1.rollNumber)
var student2 = student{name:"Arjit", rollNumber:13}
// set the member value
student2.rollNumber=24
student2.name = "Bungi"
fmt.Printf("\nstudent2 details\n--------------\n")
fmt.Printf("Name : %s\n", student2.name)
fmt.Printf("Rollnumber : %d\n", student2.rollNumber)
}
Output
student1 details
--------------
Name : Anu
Rollnumber : 14
student2 details
--------------
Name : Bungi
Rollnumber : 24
Use Pointers to Modify Go Struct Values
Assigning one struct variable to another normally copies the complete struct value. Changes made to the copy do not affect the original variable. Use a pointer when a function or method needs to update the original struct or when copying a large struct would be unnecessary.
package main
import "fmt"
type Student struct {
Name string
RollNumber int
}
func updateRollNumber(student *Student, number int) {
student.RollNumber = number
}
func main() {
student := Student{Name: "Maya", RollNumber: 21}
updateRollNumber(&student, 25)
fmt.Println(student.RollNumber)
}
Output
25
Go automatically dereferences a struct pointer when you access a field with dot notation. Therefore, student.RollNumber can be used instead of writing (*student).RollNumber.
Define Methods on Go Struct Types
You can associate behavior as well to structs, in addition to properties, in the form of functions. In the following example, we have a struct defined, and an associated method to the Student struct.
example.go
package main
import "fmt"
// struct definition
type Student struct {
name string
rollNumber int
}
// associate method to Strudent struct type
func (s Student) PrintDetails() {
fmt.Println("Student Details\n---------------")
fmt.Println("Name :", s.name)
fmt.Println("Roll Number :", s.rollNumber)
}
func main() {
var stud1 = Student{name:"Anu", rollNumber:14}
stud1.PrintDetails()
}
Output
Student Details
---------------
Name : Anu
Roll Number : 14
The identifier between func and the method name is the receiver. A value receiver, such as (s Student), receives a copy of the struct. A pointer receiver, such as (s *Student), can modify the original value.
Update Struct Fields with a Pointer Receiver Method
package main
import "fmt"
type Student struct {
Name string
RollNumber int
}
func (s *Student) ChangeRollNumber(number int) {
s.RollNumber = number
}
func main() {
student := Student{Name: "Maya", RollNumber: 21}
student.ChangeRollNumber(25)
fmt.Println(student.RollNumber)
}
Output
25
Create Anonymous Structs for Temporary Data
An anonymous struct is declared without defining a separate named type. It is useful for small, local values that are used only once, such as test data or a temporary grouping of fields.
package main
import "fmt"
func main() {
book := struct {
Title string
Pages int
}{
Title: "Go Basics",
Pages: 240,
}
fmt.Println(book.Title, book.Pages)
}
Output
Go Basics 240
Store Go Struct Values in a Slice
A slice of structs is a common way to maintain a variable-length collection of records. Each item in the slice has the same struct type.
package main
import "fmt"
type Student struct {
Name string
RollNumber int
}
func main() {
students := []Student{
{Name: "Maya", RollNumber: 21},
{Name: "Ravi", RollNumber: 22},
{Name: "Neha", RollNumber: 23},
}
for _, student := range students {
fmt.Printf("%s: %d\n", student.Name, student.RollNumber)
}
}
Output
Maya: 21
Ravi: 22
Neha: 23
Embed Structs to Compose Related Go Types
Struct embedding places one type inside another struct without assigning an explicit field name. The embedded type’s exported fields and methods are promoted, so they can be accessed through the outer struct. Embedding supports composition; it is not class inheritance.
package main
import "fmt"
type Address struct {
City string
Country string
}
type Employee struct {
Name string
Address
}
func main() {
employee := Employee{
Name: "Maya",
Address: Address{
City: "Pune",
Country: "India",
},
}
fmt.Println(employee.Name)
fmt.Println(employee.City)
fmt.Println(employee.Address.Country)
}
Output
Maya
Pune
India
Use Go Struct Tags with JSON Encoding
A struct tag is metadata attached to a field declaration. Packages can inspect tags through reflection and use them to control encoding, validation, database mapping, or other behavior. The encoding/json package, for example, reads json tags to determine object property names.
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string `json:"name"`
RollNumber int `json:"roll_number"`
Password string `json:"-"`
}
func main() {
student := Student{
Name: "Maya",
RollNumber: 21,
Password: "secret",
}
data, err := json.Marshal(student)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
}
Output
{"name":"Maya","roll_number":21}
The tag json:"-" tells the JSON encoder to omit the Password field. Struct tags are string literals and must use the format expected by the package that reads them.
Compare Go Struct Values
Two struct values can be compared with == and != when every field in the struct is itself comparable. Strings, numbers, Boolean values, pointers, channels, interfaces, and arrays of comparable values are comparable. Slices, maps, and functions are not comparable, so a struct containing one of those field types cannot be compared directly.
package main
import "fmt"
type Point struct {
X int
Y int
}
func main() {
point1 := Point{X: 10, Y: 20}
point2 := Point{X: 10, Y: 20}
point3 := Point{X: 15, Y: 20}
fmt.Println(point1 == point2)
fmt.Println(point1 == point3)
}
Output
true
false
Go Struct vs Interface
A struct and an interface serve different purposes. A struct defines concrete data by listing fields. An interface defines required behavior by listing method signatures. A struct satisfies an interface automatically when its method set contains all methods required by that interface; no explicit declaration is needed.
package main
import "fmt"
type Describer interface {
Describe() string
}
type Product struct {
Name string
}
func (p Product) Describe() string {
return "Product: " + p.Name
}
func printDescription(value Describer) {
fmt.Println(value.Describe())
}
func main() {
product := Product{Name: "Keyboard"}
printDescription(product)
}
Output
Product: Keyboard
Common Go Struct Mistakes
- Using lowercase fields across packages: fields beginning with lowercase letters are not exported. Use uppercase field names when another package must access them.
- Expecting assignment to share the same value: assigning a struct to another variable copies it. Use a pointer when both variables must refer to the same value.
- Using a value receiver for a modifying method: changes made through a value receiver affect only its copy. Use a pointer receiver to update the original struct.
- Depending on positional struct literals: literals without field names can break when the field order changes. Named fields are clearer for most application code.
- Comparing structs with slice or map fields: such structs cannot be compared directly with
==. - Assuming embedding is inheritance: embedding promotes fields and methods, but it does not create an inheritance hierarchy.
Go Struct Frequently Asked Questions
What is a struct in Go?
A struct is a user-defined Go type that groups zero or more named fields. The fields can have different types and are stored together as one value.
How do I initialize a Go struct?
You can initialize a struct with a struct literal, such as Student{Name: "Maya", RollNumber: 21}. Fields omitted from a named-field literal receive their zero values.
When should a Go struct method use a pointer receiver?
Use a pointer receiver when the method must modify the original value, when the struct is large enough that copying should be avoided, or when receiver consistency requires the type’s methods to use pointers.
Can a Go struct contain another struct?
Yes. A struct may contain another struct as a named field or embed it as an anonymous field. Named fields make the relationship explicit, while embedding promotes the embedded type’s accessible fields and methods.
Can Go structs have methods?
Yes. A method is declared as a function with a receiver parameter whose base type is defined in the same package. Methods can use either value receivers or pointer receivers.
Go Struct Tutorial QA Checklist
- Confirm that each struct literal uses field names where field order should not matter.
- Verify that fields intended for use from another package begin with uppercase letters.
- Check that methods modifying struct fields use pointer receivers.
- Confirm that JSON tags use valid quoted tag syntax and match the expected property names.
- Ensure struct comparisons are used only when every field type is comparable.
- Run each Go example and verify that its displayed output matches the program.
Summary of Go Structures
Go structs provide a direct way to group related data into reusable types. You can initialize them with struct literals, access fields with dot notation, pass pointers when values must be modified, define methods with receivers, compose types through embedding, and attach metadata through struct tags. Interfaces complement structs by describing behavior rather than storing concrete fields.
In this Go Tutorial, we learned what a structure is in Go programming, and how to use it, with the help of examples.
TutorialKart.com