Question

Go Method Receiver Syntax Explained: Parentheses Before a Function Name

Question

In Go, I found function declarations like these:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // ...
}

func (s *GracefulServer) BlockingClose() bool {
    // ...
}

What do the parts in parentheses before the function name mean, such as (h handler) and (s *GracefulServer)?

What does the full declaration mean when those parts are included?

The main point of confusion is not the difference between functions and methods in general, but specifically the meaning of the syntax that appears before the function name.

Short Answer

By the end of this page, you will understand that the extra parentheses before a Go function name define a receiver, which makes the function a method attached to a type. You will learn how value receivers and pointer receivers work, how to read declarations like func (s *Server) Start(), and when each style is used in real Go code.

Concept

In Go, a declaration like this:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // ...
}

is not an ordinary function. It is a method.

The part before the method name:

(h handler)

is called the receiver.

A receiver says:

  • this method belongs to the type handler
  • inside the method, that value will be available through the name h

So this method can be read as:

  • ServeHTTP is a method on the type handler
  • when called, the current handler value is referred to as h

Similarly:

func (s *GracefulServer) BlockingClose() bool {
    // ...
}

means:

  • BlockingClose is a method on *GracefulServer
  • the receiver variable is named s
  • s is a pointer to GracefulServer
  • the method returns a bool

Why this matters

Methods let you attach behavior to types.

For example:

  • a User type can have a FullName() method
  • a BankAccount type can have a Deposit() method
  • an HTTP handler type can have a ServeHTTP() method

This keeps data and behavior connected in a clean way.

Receiver syntax structure

A Go method declaration looks like this:

func (receiverName ReceiverType) MethodName(parameters) returnType {
    // method body
}

Example:

func (u User) FullName() string {
    return u.FirstName + " " + u.LastName
}

Here:

  • u is the receiver variable name
  • User is the receiver type
  • FullName is the method name

Value receiver vs pointer receiver

There are two common receiver forms.

Value receiver

func (h handler) ServeHTTP(...) {
    // h is a copy of the value
}

This means the method receives a copy of the value.

Use this when:

  • the method does not need to modify the original value
  • the type is small and cheap to copy

Pointer receiver

func (s *GracefulServer) BlockingClose() bool {
    // s points to the original value
}

This means the method receives a pointer to the value.

Use this when:

  • the method needs to modify the original struct
  • copying the value would be expensive
  • the type contains shared state like mutexes, buffers, or connections

Important idea

This syntax does not mean the method is taking an extra normal parameter in front of the function name.

It is declaring the receiver, which is what makes the function a method tied to a type.

So these are different:

Ordinary function:

func ServeHTTP(h handler, w http.ResponseWriter, r *http.Request) {
    // ...
}

Method:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // ...
}

The method is called on a value, like:

h.ServeHTTP(w, r)

instead of:

ServeHTTP(h, w, r)

Mental Model

Think of a Go type as a tool, and a method as an action that tool knows how to perform.

  • the type is the object
  • the receiver is the label for "this object"
  • the method is the action attached to it

For example, imagine a Car type.

func (c Car) Drive() {
    // ...
}

You can read this as:

  • "A Car has a Drive behavior"
  • inside the method, c means "this car"

So the receiver is similar to saying this instance.

If you have seen other languages, it is a bit like:

  • this in Java or C#
  • self in Python

Go just writes it explicitly in the method declaration:

func (c Car) Drive()

instead of hiding it behind a keyword.

A pointer receiver is like saying:

  • "work with the real car itself"

A value receiver is like saying:

  • "work with a copy of the car"
Take Quiz

Syntax and Examples

Basic syntax

Regular function

func add(a int, b int) int {
    return a + b
}

This is a normal function. It is not attached to any type.

Method with a value receiver

type Counter struct {
    Value int
}

func (c Counter) Display() int {
    return c.Value
}

Display is a method on Counter.

  • receiver name: c
  • receiver type: Counter

Call it like this:

counter := Counter{Value: 5}
fmt.Println(counter.Display())

Method with a pointer receiver

type Counter struct {
    Value int
}

func (c *Counter) Increment() {
    c.Value++
}

This method can change the original Counter.

Call it like this:

counter := Counter{Value: 5}
counter.Increment()
fmt.Println(counter.Value) // 6

Example matching the original question

type handler struct{}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello")
}

This means handler has a ServeHTTP method.

If a type has the right method set, it can satisfy interfaces such as http.Handler.

Another example:

type GracefulServer struct {
    closed bool
}

func (s *GracefulServer) BlockingClose() bool {
    if s.closed {
        return false
    }
    s.closed = true
    return true
}

This uses a pointer receiver because the method changes the server state.

Step by Step Execution

Consider this example:

package main

import "fmt"

type Counter struct {
    Value int
}

func (c *Counter) Increment() {
    c.Value++
}

func main() {
    counter := Counter{Value: 10}
    counter.Increment()
    fmt.Println(counter.Value)
}

Step by step

1. Define a type

type Counter struct {
    Value int
}

This creates a struct type named Counter.

2. Define a method on that type

func (c *Counter) Increment() {
    c.Value++
}

This says:

  • Increment is a method on *Counter
  • c points to the Counter value that called the method

3. Create a value

counter := Counter{Value: 10}

Now counter.Value is 10.

4. Call the method

counter.Increment()

Go uses the counter value as the receiver.

Inside the method:

  • c refers to counter
  • c.Value++ changes the original struct value to 11

5. Print the result

fmt.Println(counter.Value)

Output:

11

Compare with a value receiver

func (c Counter) IncrementWrong() {
    c.Value++
}

If you call this method, it only changes a copy.

counter := Counter{Value: 10}
counter.IncrementWrong()
fmt.Println(counter.Value)

Output:

10

That is because c is a copy, not the original value.

Real World Use Cases

Methods with receivers are used throughout Go code.

HTTP handlers

A common real example is:

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // handle request
}

This lets a type satisfy the http.Handler interface.

Use case:

  • web servers
  • middleware
  • API routing

State-changing services

func (s *Server) Shutdown() error {
    // update internal state
    return nil
}

Pointer receivers are common for:

  • servers
  • database clients
  • caches
  • job queues

Domain models

func (u User) FullName() string {
    return u.FirstName + " " + u.LastName
}

Value receivers are often used for read-only behavior:

  • formatting values
  • computing derived data
  • helper methods on small structs

Validation methods

func (c Config) IsValid() bool {
    return c.Port > 0
}

Useful for:

  • configuration loading
  • input validation
  • reusable checks

Data manipulation

func (b *Balance) Deposit(amount int) {
    b.Total += amount
}

Useful in:

  • financial logic
  • counters
  • inventory systems
  • metrics collection
Take Quiz

Real Codebase Usage

In real Go projects, receiver methods are used to organize behavior around types.

Common patterns

1. Guard clauses in methods

func (s *Server) Start() error {
    if s == nil {
        return fmt.Errorf("server is nil")
    }
    if s.running {
        return nil
    }
    s.running = true
    return nil
}

This is common when a method depends on internal state.

2. Validation methods

func (c Config) Validate() error {
    if c.Port <= 0 {
        return fmt.Errorf("invalid port")
    }
    return nil
}

This keeps validation logic close to the data it validates.

3. Mutating methods use pointer receivers

func (u *User) SetEmail(email string) {
    u.Email = email
}

If a method changes fields, pointer receivers are the usual choice.

4. Interface implementation

type Stringer interface {
    String() string
}

func (u User) String() string {
    return u.Name
}

A method can make a type satisfy an interface without extra declarations.

5. Methods for encapsulation

func (o Order) Total() float64 {
    return o.Price * float64(o.Quantity)
}

This gives a clear API:

order.Total()

instead of exposing every calculation everywhere.

Choosing receiver style consistently

In production code, developers usually keep receiver choice consistent for a type.

If some methods need pointer receivers, many teams make most or all methods use pointer receivers too, especially for structs with state.

Common Mistakes

1. Thinking the receiver is just a normal parameter

This is a very common first impression.

Broken mental model:

func (c Counter) Show()

This is not a function with a strange parameter before the name. It is a method declaration.

Remember:

  • receiver syntax makes it a method
  • methods are called with dot syntax
counter.Show()

2. Using a value receiver when you need to modify the original

Broken example:

type Counter struct {
    Value int
}

func (c Counter) Increment() {
    c.Value++
}

This only modifies a copy.

Fix:

func (c *Counter) Increment() {
    c.Value++
}

3. Mixing pointer and value receivers carelessly

Broken style:

func (u User) Name() string { return u.name }
func (u *User) SetName(name string) { u.name = name }

This can be valid, but beginners often do it without understanding method sets and consistency.

Safer rule:

  • if the type has methods that mutate state, prefer pointer receivers consistently

4. Forgetting that the receiver name is just a local variable name

func (s *Server) Start() {}

Here s is not special. It could be another name:

func (server *Server) Start() {}

Short names are conventional, but they are just variable names.

5. Trying to define methods on types you do not own

You can define methods on named types in your package, but not directly on arbitrary external types.

For example, this kind of idea is not how Go is usually used:

// not a normal pattern for external package types
func (r http.Request) MyMethod() {}

Instead, define your own type if needed.

6. Confusing return type with receiver type

Example:

func (s *GracefulServer) BlockingClose() bool
  • *GracefulServer is the receiver type
  • bool is the return type

They are separate parts of the declaration.

Comparisons

Function vs method

FeatureFunctionMethod
Attached to a typeNoYes
Has receiverNoYes
Call styleadd(1, 2)counter.Increment()
Organizes behavior around dataLess directlyYes

Function example

func add(a int, b int) int {
    return a + b
}

Method example

func (c *Counter) Increment() {
    c.Value++
}

Value receiver vs pointer receiver

Receiver styleExampleWorks onCan modify original?Common use
Value receiver(c Counter)a copyNosmall, read-only behavior
Pointer receiver(c *Counter)original value via pointerYesstate changes, large structs

Method call vs function call with explicit argument

These may look conceptually related:

counter.Increment()

and

Increment(counter)

But in Go they are declared differently and used differently.

StyleDeclarationCall
Functionfunc Increment(c Counter)Increment(counter)
Methodfunc (c Counter) Increment()counter.Increment()

Methods are the standard way to attach behavior to a type.

Take Quiz

Cheat Sheet

Receiver syntax

func (name Type) MethodName(params) returnType {
    // ...
}

Examples

Value receiver

func (u User) FullName() string {
    return u.FirstName + " " + u.LastName
}

Pointer receiver

func (u *User) SetName(name string) {
    u.Name = name
}

How to read it

func (s *Server) Start() error

Read as:

  • Start is a method
  • receiver variable: s
  • receiver type: *Server
  • return type: error

Rules of thumb

  • Use a value receiver for read-only behavior on small values.
  • Use a pointer receiver if the method modifies the original value.
  • Use a pointer receiver if copying the struct would be expensive.
  • Keep receiver style consistent across a type when possible.

Common call style

user.FullName()
server.Start()

Common confusion

This:

func (h handler) ServeHTTP(...)

means method with receiver, not a parameter before the function name.

FAQ

What is the thing in parentheses before a function name in Go?

It is the receiver. It makes the declaration a method attached to a type.

Is (h handler) a function parameter?

No. It is not a regular parameter. It is receiver syntax used for methods.

What does *GracefulServer mean in the receiver?

It means the method has a pointer receiver, so it works with a pointer to GracefulServer and can modify the original value.

What is the difference between (c Counter) and (c *Counter)?

(c Counter) gets a copy of the value. (c *Counter) gets a pointer to the original value.

When should I use a pointer receiver in Go?

Use one when the method changes the struct, when the struct is large, or when you want consistent behavior across methods.

Are methods just functions in Go?

A method is a special kind of function that is attached to a type through a receiver.

Why does ServeHTTP often use a receiver?

Because Go's HTTP system uses interfaces, and a type can satisfy http.Handler by implementing the ServeHTTP method.

Can the receiver variable name be anything?

Yes. Names like h, s, and c are conventional, but any valid local name can be used.

Take Quiz

Mini Project

Description

Build a small Go program with a BankAccount type to practice method receivers. This project shows the difference between read-only methods and state-changing methods, which is exactly the reason Go uses value and pointer receivers.

Goal

Create a BankAccount type with methods to read the balance and deposit money using the correct receiver types.

Requirements

  • Define a BankAccount struct with an owner name and balance.
  • Add a method that returns a formatted account summary.
  • Add a method that deposits money into the account.
  • Use a pointer receiver for the method that changes the balance.
  • Create an account in main and show the balance before and after a deposit.
Take Quiz

Keep learning

Related questions

View more