Skip to main content

Structs in Go

Structs are fundamental building blocks in Go, allowing you to group related data fields into user-defined types. This empowers you to create logical representations of entities and efficiently manage their attributes.

Defining Structs with Named Fields and Types

type Person struct {
Name string
Age int
}

type Point struct {
X float64
Y float64
}

Explanation:

  • type keyword declares a new struct type.
  • Each field within the struct is defined with its name and data type (e.g., string, int, float64).
  • These named fields provide clear meaning and organization to your data.

Basic Usage of Structs

person := Person{"John Doe", 30}
point := Point{2.5, 4.2}

fmt.Println("Person:", person.Name, person.Age)
fmt.Println("Point:", point.X, point.Y)

Explanation:

  • You can create struct instances (person, point) using the struct type name and providing values for each field (either in order or by name).
  • Access struct fields using the dot notation (e.g., person.Name, point.Y).
  • This code demonstrates how to create and utilize structs to store and retrieve data.

Accessing Struct Fields using Dot Notation

person := Person{Name: "Jane Doe", Age: 25}

age := person.Age

person.Name = "Alice Smith"

fmt.Println("Person:", person.Name, person.Age)

Explanation:

  • The dot operator (.) is used to access individual fields of a struct instance.
  • You can access fields for reading (age := person.Age) or writing (person.Name = "Alice Smith").
  • This code showcases how to interact with and modify the data within a struct.

Initializing Structs with Literal Values and Struct Literals

// Literal values
person := Person{"Bob", 40}

// Struct literals
point := Point{X: 1.0, Y: 2.0}
anonymous := struct {
Name string
}{"Anonymous"}

fmt.Println("Person:", person)
fmt.Println("Point:", point)
fmt.Println("Anonymous:", anonymous.Name)

Explanation:

  • Literal values can be used to directly initialize fields when creating a struct instance.
  • Struct literals provide a concise way to create structs without explicitly mentioning fields: {X: 1.0, Y: 2.0}.
  • Anonymous structs (defined without a name) can be useful for temporary data or specific use cases.

Passing Structs by Value and by Reference

func updateAge(person Person) {
person.Age++ // Doesn't modify original `person`
}

func updateAgeByRef(person *Person) {
(*person).Age++ // Modifies original `person` through pointer
}

person := Person{Name: "Mary", Age: 35}
updateAge(person)
fmt.Println("Person (value pass):", person.Age) // Value remains 35

updateAgeByRef(&person)
fmt.Println("Person (reference pass):", person.Age) // Value now 36

Explanation:

  • By default, structs are passed by value (copy), meaning changes within a function don't affect the original struct.
  • Use pointers (*Person) and explicit dereferencing (*person) to pass structs by reference, modifying the original struct within functions.
  • This code demonstrates the difference between passing by value and by reference, highlighting when each approach is appropriate.

Pointers to Structs and Dereferencing

person := Person{Name: "Peter", Age: 45}
personPtr := &person

fmt.Println("Name before:", person.Name)
personPtr.Name = "Updated Name" // Modify through pointer
fmt.Println("Name after:", person.Name) // Value changed

Explanation:

  • Pointers (&person) store memory addresses of structs, allowing you to indirectly access and modify struct values.
  • Dereferencing (*personPtr) retrieves the actual struct value at the stored address.
  • Pointers offer flexibility and efficiency when dealing with large or complex structs, as you can modify them without copying the entire data.