Structs are a fundamental part of Go's type system, enabling the creation of custom data types by grouping together variables. They provide a way to organize and manage related data efficiently. Understanding struct composition, embedded structs, and the use of tags and reflection is essential for creating flexible and reusable structures in Go.
A struct is a collection of fields, each with a name and type.
gotype Person struct {
FirstName string
LastName string
Age int
}
p := Person{
FirstName: "John",
LastName: "Doe",
Age: 30,
}
fmt.Println(p.FirstName) // Output: John
p.FirstName
).Embedded structs allow one struct to be nested within another, providing a form of composition. This helps create more flexible and reusable structures.
gotype Address struct {
Street string
City string
}
type Person struct {
FirstName string
LastName string
Address
}
p := Person{
FirstName: "Jane",
LastName: "Smith",
Address: Address{Street: "123 Main St", City: "Metropolis"},
}
fmt.Println(p.Street) // Output: 123 Main St
Address
struct is embedded within the Person
struct.Address
) are promoted to the outer struct (Person
), allowing direct access (p.Street
).Embedded structs can also be anonymous.
gotype Job struct {
Title string
Salary int
}
type Employee struct {
Person
Job
}
e := Employee{
Person: Person{FirstName: "Alice", LastName: "Brown", Address: Address{Street: "456 Elm St", City: "Gotham"}},
Job: Job{Title: "Engineer", Salary: 100000},
}
fmt.Println(e.FirstName) // Output: Alice
fmt.Println(e.Title) // Output: Engineer
Person
and Job
are embedded in Employee
, allowing access to their fields directly through the Employee
instance.Struct tags provide metadata for struct fields, often used for serialization, validation, or other purposes. Reflection allows inspecting these tags at runtime.
Struct tags are defined using backticks and follow the field declaration.
gotype User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
encoding/json
to control JSON encoding and decoding.Reflection in Go is provided by the reflect
package, enabling dynamic inspection and manipulation of types and values.
gopackage main
import (
"fmt"
"reflect"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
u := User{ID: 1, Name: "John Doe", Email: "john@example.com"}
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("Field: %s, Tag: %s\n", field.Name, field.Tag)
}
}
reflect.TypeOf
function returns the reflect.Type
of a value.Field
method retrieves information about each field, including tags.Methods can be associated with structs, allowing you to define behavior related to the data the struct represents.
gotype Rectangle struct {
Width, Height float64
}
// Method to calculate area
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
rect := Rectangle{Width: 10, Height: 5}
fmt.Println(rect.Area()) // Output: 50
r Rectangle
) and can access the struct's fields.Using pointer receivers allows methods to modify the struct's fields.
gotype Counter struct {
Count int
}
// Method to increment count
func (c *Counter) Increment() {
c.Count++
}
ctr := Counter{Count: 0}
ctr.Increment()
fmt.Println(ctr.Count) // Output: 1
*Counter
) allow methods to modify the original struct.Structs in Go are powerful tools for creating custom data types and organizing related data. Embedded structs provide a means of composition, enabling flexible and reusable structures. Tags and reflection add metadata and dynamic capabilities, enhancing the utility of structs. By mastering these concepts, you can effectively leverage structs to build robust and maintainable Go programs.