Menu
Coddy logo textTech

Pass by Value vs Reference

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 21 of 107.

Go is a pass-by-value language. When you pass a variable to a function, Go creates a copy of that value. This means changes inside the function don't affect the original variable.

func double(n int) {
    n = n * 2
}

func main() {
    x := 10
    double(x)
    fmt.Println(x)  // 10 (unchanged)
}

The same applies to structs. Passing a struct to a function copies all its fields, so modifications inside the function are lost.

type Person struct {
    Name string
    Age  int
}

func birthday(p Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(alice)
    fmt.Println(alice.Age)  // 30 (unchanged)
}

To modify the original value, pass a pointer instead. The pointer itself is copied, but it still points to the same memory address, allowing you to change the original data.

func birthday(p *Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(&alice)
    fmt.Println(alice.Age)  // 31 (modified!)
}

Use pointers when you need to modify the original value or when passing large structs to avoid expensive copying. Use values when you want to protect the original data from unintended changes.

challenge icon

Challenge

Easy

Let's build a shopping cart system that demonstrates the difference between passing structs by value versus by pointer. You'll see firsthand how only pointer parameters can modify the original data.

You'll organize your code across two files:

  • cart.go: Define a CartItem struct with Name (string), Price (float64), and Quantity (int) fields. Create two functions that attempt to update the quantity:
    • UpdateQuantityByValue takes a CartItem (by value) and a new quantity, then sets the item's quantity to the new value
    • UpdateQuantityByPointer takes a *CartItem (pointer) and a new quantity, then sets the item's quantity to the new value
    Also create a Total method on CartItem that returns the price multiplied by quantity.
  • main.go: Read item details from input, create a CartItem, then demonstrate both update approaches. First try updating with the value function and show the result, then update with the pointer function and show the result again.

The following inputs will be provided:

  • Line 1: Item name
  • Line 2: Price (float)
  • Line 3: Initial quantity (integer)
  • Line 4: New quantity to set (integer)

Output format:

Initial: [Name] x[Quantity] = $[Total]
After value update: [Name] x[Quantity] = $[Total]
After pointer update: [Name] x[Quantity] = $[Total]

For example, given Laptop, 999.99, 1, and 3, your output should be:

Initial: Laptop x1 = $999.99
After value update: Laptop x1 = $999.99
After pointer update: Laptop x3 = $2999.97

Notice how the quantity stays at 1 after the value update (the function modified a copy), but changes to 3 after the pointer update (the function modified the original). Format totals with two decimal places.

Cheat sheet

Go is a pass-by-value language. When you pass a variable to a function, Go creates a copy of that value, so changes inside the function don't affect the original variable.

func double(n int) {
    n = n * 2
}

func main() {
    x := 10
    double(x)
    fmt.Println(x)  // 10 (unchanged)
}

The same applies to structs. Passing a struct to a function copies all its fields:

type Person struct {
    Name string
    Age  int
}

func birthday(p Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(alice)
    fmt.Println(alice.Age)  // 30 (unchanged)
}

To modify the original value, pass a pointer. The pointer itself is copied, but it still points to the same memory address:

func birthday(p *Person) {
    p.Age++
}

func main() {
    alice := Person{Name: "Alice", Age: 30}
    birthday(&alice)
    fmt.Println(alice.Age)  // 31 (modified!)
}

Use pointers when you need to modify the original value or when passing large structs to avoid expensive copying. Use values when you want to protect the original data from unintended changes.

Try it yourself

package main

import (
	"fmt"
)

func main() {
	// Read input
	var name string
	var price float64
	var initialQty, newQty int

	fmt.Scanln(&name)
	fmt.Scanln(&price)
	fmt.Scanln(&initialQty)
	fmt.Scanln(&newQty)

	// TODO: Create a CartItem with the input values

	// TODO: Print initial state using format:
	// fmt.Printf("Initial: %s x%d = $%.2f\n", ...)

	// TODO: Try updating quantity using UpdateQuantityByValue
	// Then print the result (notice quantity won't change)

	// TODO: Update quantity using UpdateQuantityByPointer
	// Then print the result (notice quantity will change)
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming