Structs
Go has no classes. A struct is Go's way of grouping related fields into one named type, and methods get attached to that type separately, outside the struct definition itself.
Defining and creating a struct
package main import "fmt" type Account struct { Owner string Balance float64 } func main() { acc := Account{Owner: "Jamie", Balance: 100} fmt.Println(acc.Owner, acc.Balance) }
Jamie 100
type Account struct { ... } declares a new type with two named fields. Account{Owner: "Jamie", Balance: 100} creates a value of that type, and . reaches into a field exactly like in most other languages here.
Owner is exported — visible outside the package it's defined in. A lowercase name like owner would only be visible inside the same package. Go uses capitalization itself as the public/private marker, instead of keywords like public or private.Methods with a receiver
A method is a function with an extra receiver argument before its name, tying it to a particular type:
package main import "fmt" type Account struct { Owner string Balance float64 } func (a Account) Describe() string { return fmt.Sprintf("%s has $%.2f", a.Owner, a.Balance) } func main() { acc := Account{Owner: "Jamie", Balance: 100} fmt.Println(acc.Describe()) }
Jamie has $100.00
func (a Account) Describe() string attaches Describe to the Account type — a is the receiver, a local name for whichever Account value the method was called on, similar to this or self in other languages but declared explicitly instead of implied.
Value receivers copy; pointer receivers don't
Describe above uses a value receiver, which means a is a full copy of the struct — fine for reading, but a method that needs to actually change the struct needs a pointer receiver instead:
package main import "fmt" type Account struct { Owner string Balance float64 } func (a *Account) Deposit(amount float64) { a.Balance += amount } func main() { acc := Account{Owner: "Jamie", Balance: 100} acc.Deposit(50) fmt.Println(acc.Balance) }
150
func (a *Account) Deposit(...) takes a pointer receiver, so a refers to the original struct rather than a copy — changes made through a inside Deposit are visible on acc after the call returns. Go automatically takes acc's address for you when you call acc.Deposit(50), even though acc itself isn't a pointer.