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:
ServeHTTPis a method on the typehandler- when called, the current
handlervalue is referred to ash
Similarly:
func (s *GracefulServer) BlockingClose() bool {
// ...
}
means:
BlockingCloseis a method on*GracefulServer- the receiver variable is named
s sis a pointer toGracefulServer- the method returns a
bool
Why this matters
Methods let you attach behavior to types.
For example:
- a
Usertype can have aFullName()method - a
BankAccounttype can have aDeposit()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:
uis the receiver variable nameUseris the receiver typeFullNameis 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
Carhas aDrivebehavior" - inside the method,
cmeans "this car"
So the receiver is similar to saying this instance.
If you have seen other languages, it is a bit like:
thisin Java or C#selfin 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"
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:
Incrementis a method on*Countercpoints to theCountervalue 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:
crefers tocounterc.Value++changes the original struct value to11
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
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
*GracefulServeris the receiver typeboolis the return type
They are separate parts of the declaration.
Comparisons
Function vs method
| Feature | Function | Method |
|---|---|---|
| Attached to a type | No | Yes |
| Has receiver | No | Yes |
| Call style | add(1, 2) | counter.Increment() |
| Organizes behavior around data | Less directly | Yes |
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 style | Example | Works on | Can modify original? | Common use |
|---|---|---|---|---|
| Value receiver | (c Counter) | a copy | No | small, read-only behavior |
| Pointer receiver | (c *Counter) | original value via pointer | Yes | state 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.
| Style | Declaration | Call |
|---|---|---|
| Function | func Increment(c Counter) | Increment(counter) |
| Method | func (c Counter) Increment() | counter.Increment() |
Methods are the standard way to attach behavior to a type.
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:
Startis 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.
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
BankAccountstruct 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
mainand show the balance before and after a deposit.
Keep learning
Related questions
Are Go Maps Passed by Value or Reference?
Learn Go map parameter and return semantics: maps are passed by value, while copies share underlying data. Know when map pointers are useful.
Authentication for Go REST APIs: Sessions, Tokens, and Middleware
Learn practical authentication patterns for Go REST APIs, including password hashing, server sessions, bearer tokens, middleware, and security rules.
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.