Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A method value in Go is a function value created by binding a specific method to a specific receiver instance. When evaluated, the expression yields a closure that implicitly retains the receiver, allowing the method to be invoked later with only its standard parameters.

Syntax and Type Signature

A method value is formed using the selector syntax instance.MethodName without invoking it (omitting the parentheses). If a type T has a method M with the signature func (r T) M(arg int) string, and t is an instance of T, the method value t.M evaluates to a standard function of type func(int) string. The receiver is abstracted away from the resulting function signature.
package main

type Counter struct {
    value int
}

func (c *Counter) Add(amount int) int {
    c.value += amount
    return c.value
}

func main() {
    c := &Counter{value: 10}

    // Method value creation: binds the specific receiver 'c' to the method 'Add'
    fn := c.Add 

    // The resulting type is func(int) int
    // The receiver 'c' is implicitly passed during invocation
    result := fn(5) // result is 15
    _ = result
}

Receiver Evaluation and Binding

The exact state of the receiver is captured at the moment the method value is evaluated, not when the resulting function is executed. The behavior depends strictly on whether the method is defined with a value receiver or a pointer receiver:
  • Value Receivers: If the method is defined with a value receiver, Go creates a copy of the receiver’s state at the exact time the method value is assigned. Subsequent modifications to the original instance will not affect the state held by the method value closure.
  • Pointer Receivers: If the method is defined with a pointer receiver, the method value captures a copy of the pointer. Consequently, the method value and the original instance reference the same underlying memory, and mutations will be visible when the method value is invoked.
package main

import "fmt"

type Printer struct {
    Data string
}

func (p Printer) PrintValue() {
    fmt.Println(p.Data)
}

func (p *Printer) PrintPointer() {
    fmt.Println(p.Data)
}

func main() {
    p := Printer{Data: "Initial"}

    // Evaluated now. 'p' is copied because PrintValue has a value receiver.
    valMethod := p.PrintValue 

    // Evaluated now. The pointer to 'p' is copied because PrintPointer has a pointer receiver.
    ptrMethod := p.PrintPointer 

    p.Data = "Mutated"

    valMethod() // Outputs: "Initial" (operates on the captured copy)
    ptrMethod() // Outputs: "Mutated" (operates on the captured pointer)
}

Addressability Requirements

When deriving a method value for a pointer receiver from a value instance (as seen with p.PrintPointer in the example above), Go automatically takes the address of the value ((&p).PrintPointer). This syntactic sugar requires the underlying value to be addressable. If the value is unaddressable (e.g., the return value of a function, or a value stored in a map), creating a method value for a pointer receiver will result in a compilation error.

Nil Receivers and Evaluation-Time Panics

Because receiver evaluation and copying occur at the exact moment the method value is created, dereferencing rules apply immediately. If a method value is evaluated on a nil pointer, but the method is defined with a value receiver, the program will panic immediately during evaluation. Go must dereference the pointer to copy the value into the closure; it does not wait until the method value is invoked to trigger the panic.

Method Values vs. Method Expressions

To understand method values mechanically, it is necessary to distinguish them from method expressions:
  • Method Value (instance.MethodName): Binds the receiver. Yields a function where the receiver is hidden from the signature.
  • Method Expression (Type.MethodName): Does not bind a receiver. Yields an unbound function where the receiver must be explicitly passed as the first argument.
// Assuming the Counter type defined earlier
c := &Counter{value: 10}

// Method Value
mv := c.Add           // Type: func(int) int
mv(5)                 // Invocation

// Method Expression
me := (*Counter).Add  // Type: func(*Counter, int) int
me(c, 5)              // Invocation requires explicit receiver
Master Go with Deep Grasping Methodology!Learn More