Let's dive deep into structs in Go — one of the most fundamental and powerful data structures in the language.
A struct
in Go is a composite data type (i.e., it groups multiple values into a single unit). It's used to create custom data types that model real-world entities — like User
, Product
, Book
, Transaction
, etc.
Think of a struct
as a class without methods, though we can attach methods to structs in Go.
type User struct {
Name string
Age int
}
User
is a new custom type.- It has two fields:
Name
andAge
.
This is definition only. To use it, we need to create instances.
user := User{Name: "Skyy", Age: 29}
user := User{"Skyy", 29}
✅ Not recommended for readability
var user User
user.Name = "Skyy"
user.Age = 29
fmt.Println(user.Name) // "Skyy"
user.Age = 30
If you declare a struct without assigning fields:
var u User
fmt.Println(u) // {"" 0}
- All fields get zero values (
""
for string,0
for int, etc.)
Just like with any type, we can create pointers to structs:
u := &User{Name: "Skyy", Age: 29}
fmt.Println(u.Name) // Go automatically dereferences u
Go provides syntactic sugar: u.Name
is the same as (*u).Name
.
This is very useful when passing structs to functions or mutating data.
We can associate methods with a struct type:
func (u User) Greet() {
fmt.Println("Hello,", u.Name)
}
This is a value receiver – works on a copy of
User
.
If we want to mutate fields, use a pointer receiver:
func (u *User) UpdateName(newName string) {
u.Name = newName
}
Go doesn’t support inheritance but allows embedding.
type Address struct {
City string
State string
}
type Employee struct {
Name string
Age int
Address // embedded struct
}
Now you can access Employee.City
directly:
emp := Employee{Name: "Skyy", Age: 29, Address: Address{"Kolkata", "WB"}}
fmt.Println(emp.City) // "Kolkata"
Struct tags add metadata used by packages like encoding/json
, gorm
, etc.
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
Used with packages like:
json.Marshal(user) // produces {"name":"Skyy","age":29}
Quick way to declare a one-time struct:
emp := struct {
Name string
Age int
}{"Skyy", 29}
users := []User{
{Name: "Alice", Age: 25},
{Name: "Bob", Age: 30},
}
Tip | Description |
---|---|
Use field names when initializing | Improves readability |
Use pointer receivers for mutation | Avoid unnecessary copies |
Group related fields logically | Easier to maintain and understand |
Use struct tags for API/database | Interoperability with other systems |
Use embedded structs for reuse | Clean, DRY design without inheritance complexity |
type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
InStock bool `json:"in_stock"`
}
func (p *Product) ApplyDiscount(discount float64) {
p.Price = p.Price - (p.Price * discount / 100)
}
Let's dive deep into structs in Go — one of the most fundamental and powerful data structures in the language.
A struct
in Go is a composite data type (i.e., it groups multiple values into a single unit). It's used to create custom data types that model real-world entities — like User
, Product
, Book
, Transaction
, etc.
Think of a struct
as a class without methods, though we can attach methods to structs in Go.
type User struct {
Name string
Age int
}
User
is a new custom type.- It has two fields:
Name
andAge
.
This is definition only. To use it, we need to create instances.
user := User{Name: "Skyy", Age: 29}
user := User{"Skyy", 29}
✅ Not recommended for readability
var user User
user.Name = "Skyy"
user.Age = 29
fmt.Println(user.Name) // "Skyy"
user.Age = 30
If you declare a struct without assigning fields:
var u User
fmt.Println(u) // {"" 0}
- All fields get zero values (
""
for string,0
for int, etc.)
Just like with any type, we can create pointers to structs:
u := &User{Name: "Skyy", Age: 29}
fmt.Println(u.Name) // Go automatically dereferences u
Go provides syntactic sugar: u.Name
is the same as (*u).Name
.
This is very useful when passing structs to functions or mutating data.
We can associate methods with a struct type:
func (u User) Greet() {
fmt.Println("Hello,", u.Name)
}
This is a value receiver – works on a copy of
User
.
If we want to mutate fields, use a pointer receiver:
func (u *User) UpdateName(newName string) {
u.Name = newName
}
Go doesn’t support inheritance but allows embedding.
type Address struct {
City string
State string
}
type Employee struct {
Name string
Age int
Address // embedded struct
}
Now you can access Employee.City
directly:
emp := Employee{Name: "Skyy", Age: 29, Address: Address{"Kolkata", "WB"}}
fmt.Println(emp.City) // "Kolkata"
Struct tags add metadata used by packages like encoding/json
, gorm
, etc.
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
Used with packages like:
json.Marshal(user) // produces {"name":"Skyy","age":29}
Quick way to declare a one-time struct:
emp := struct {
Name string
Age int
}{"Skyy", 29}
users := []User{
{Name: "Alice", Age: 25},
{Name: "Bob", Age: 30},
}
Tip | Description |
---|---|
Use field names when initializing | Improves readability |
Use pointer receivers for mutation | Avoid unnecessary copies |
Group related fields logically | Easier to maintain and understand |
Use struct tags for API/database | Interoperability with other systems |
Use embedded structs for reuse | Clean, DRY design without inheritance complexity |
type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
InStock bool `json:"in_stock"`
}
func (p *Product) ApplyDiscount(discount float64) {
p.Price = p.Price - (p.Price * discount / 100)
}