Skip to content
AgileLogics
5 min read

Methods

Prerequisites: Pointers

A method is a function attached to a type. The extra parameter in parentheses before the name is the receiver — the value the method is called on, similar to this or self in other languages (but named like any other parameter).

Syntax

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

rect := Rectangle{Width: 3, Height: 4}
rect.Area() // 12

By convention the receiver name is a short abbreviation of the type (r for Rectangle), not this or self.

Example

package main

import "fmt"

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func (r Rectangle) IsSquare() bool {
    return r.Width == r.Height
}

// Grow has a value receiver, so it only changes a copy.
func (r Rectangle) Grow(amount float64) {
    r.Width += amount
    r.Height += amount
}

// Methods work on any type you define, not just structs.
type Celsius float64

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

func main() {
    rect := Rectangle{Width: 3, Height: 4}
    fmt.Println(rect.Area())
    fmt.Println(rect.Perimeter())
    fmt.Println(rect.IsSquare())

    rect.Grow(10)
    fmt.Println(rect.Width)

    temp := Celsius(100)
    fmt.Println(temp.Fahrenheit())
}

Expected output

12
14
false
3
212

All the methods above use a value receiver (r Rectangle): each call works on a copy of the struct. That's perfect for methods that only read fields, and it explains why Grow had no effect — rect.Width is still 3. Methods that need to modify the receiver use a pointer receiver (r *Rectangle); those are covered in Level 2, together with interfaces.

Common mistakes

  • Writing a value-receiver method that assigns to fields and expecting the change to stick.
  • Trying to add methods to a type from another package (such as int or string directly). Define your own type first, like type Celsius float64.
  • Mixing up rect.Area (the method value) and rect.Area() (the call).

Practice

Define a Circle struct with a Radius float64 field and an Area() method using math.Pi. Print the area of a circle with radius 2, formatted to two decimal places.

Show solution
package main

import (
    "fmt"
    "math"
)

type Circle struct {
    Radius float64
}

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

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