0Pricing
Go Academy · Lesson

Methods on Structs

Value receivers vs pointer receivers

Methods on Structs is a free Go Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is a Method?

A method is a function with a receiver argument. The receiver appears between the func keyword and the method name, binding the function to a type.

Value Receiver

A value receiver receives a copy of the struct. Use when the method doesn't need to mutate state:

package main
import "fmt"

type Circle struct{ Radius float64 }

func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

func main() {
    c := Circle{Radius: 5}
    fmt.Printf("%.2f\n", c.Area()) // 78.54
}

Pointer Receiver

A pointer receiver allows the method to mutate the struct. More efficient for large structs:

package main
import "fmt"

type Counter struct{ N int }

func (c *Counter) Increment() { c.N++ }
func (c *Counter) Reset()     { c.N = 0 }

func main() {
    c := Counter{}
    c.Increment(); c.Increment()
    fmt.Println(c.N) // 2
    c.Reset()
    fmt.Println(c.N) // 0
}

When to Use Pointer Receivers

Use pointer receivers when:

  • The method needs to modify the receiver
  • The struct is large (avoids copying)
  • Consistency: if any method has a pointer receiver, all should

Use value receivers when the struct is small and the method only reads data.

Method Expressions and Values

Methods can be used as first-class values:

package main
import "fmt"

type Adder struct{ Base int }

func (a Adder) Add(n int) int { return a.Base + n }

func main() {
    a := Adder{Base: 10}
    fn := a.Add          // method value — bound to a
    fmt.Println(fn(5))   // 15
}

Methods on Non-Struct Types

You can define methods on any named type in the same package, not just structs:

package main
import "fmt"

type Celsius float64

func (c Celsius) ToFahrenheit() float64 {
    return float64(c)*9/5 + 32
}

func main() {
    t := Celsius(100)
    fmt.Println(t.ToFahrenheit()) // 212
}

Automatic Pointer Dereferencing

Go automatically takes the address or dereferences when calling methods. You don't need to write (&c).Method() manually:

package main
import "fmt"

type Box struct{ Val int }

func (b *Box) Double() { b.Val *= 2 }

func main() {
    b := Box{Val: 5}
    b.Double()           // Go auto-takes address
    fmt.Println(b.Val)   // 10
}

Chaining Methods

Return the receiver pointer to enable method chaining (builder pattern):

package main
import "fmt"

type Builder struct{ result string }

func (b *Builder) Add(s string) *Builder {
    b.result += s
    return b
}
func (b *Builder) Build() string { return b.result }

func main() {
    s := (&Builder{}).Add("Hello").Add(", ").Add("World").Build()
    fmt.Println(s)
}

String Method (fmt.Stringer)

Implement the String() string method to control how a type is printed:

package main
import "fmt"

type Point struct{ X, Y int }

func (p Point) String() string {
    return fmt.Sprintf("(%d, %d)", p.X, p.Y)
}

func main() {
    p := Point{3, 4}
    fmt.Println(p) // (3, 4)
}

Nil Pointer Receivers

A method with a pointer receiver can be called on a nil pointer — useful for default behaviors:

package main
import "fmt"

type Node struct{ Val int }

func (n *Node) Value() int {
    if n == nil { return 0 }
    return n.Val
}

func main() {
    var n *Node
    fmt.Println(n.Value()) // 0
}

Consistency Principle

In Go's standard library and idiomatic Go, all methods on a type use the same receiver kind — all pointer or all value. Mixing causes subtle bugs with interfaces.

Quick Check

Which receiver type allows a method to modify the struct's fields?

Recap: Methods

Key takeaways:

  • Methods have a receiver between func and the name
  • Value receivers: read-only, small structs
  • Pointer receivers: mutation, large structs, consistency
  • Go auto-dereferences — no need to write (&v).Method()
  • Implement String() string for custom printing

Practice Prompt

Define a BankAccount struct with a Balance float64 field. Add Deposit and Withdraw pointer-receiver methods and a String() value-receiver method.

Frequently asked questions

Is the “Methods on Structs” lesson free?

Yes — the full text of “Methods on Structs” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.

What will I learn in “Methods on Structs”?

Value receivers vs pointer receivers You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Go Academy?

No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Methods on Structs” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Go Academy lesson?

Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Defining and Using Structs
  2. Methods on Structs
  3. Constructor Patterns
  4. Anonymous Structs and Composition
← Back to Go Academy