Video Coming Soon...

Created by Zed A. Shaw Updated 2025-10-07 14:32:54

14: Reading Input

WARNING This exercise is in DRAFT status, so there may be errors. If you find any, please email me at help@learncodethehardway.com so I can fix them.

We now come to the final exercise before the end. After this you'll use what you know to make a simple Text Adventure Game before moving on to Module 2.

In this exercise you'll learn how to read basic values from a user using the fmt package you've been using to print.

Pass by Reference

Before you can use the fmt.Scan function (and friends) you need to learn about "pass by reference" vs. "pass by value." This topic will come up multiple times later, so if you don't quite get it then be patient.

Remember in Exercise 11 how I showed that a function can't change the caller? If not go look at that exercise again. This also works in the function has a variable with the same name like this:

func WontWork(a int) {
    a := 1
}

func main() {
    a := 100
    WontWork(a)
}

No matter what you do the WontWork() function cannot change a in main(), even though they have the same name. This is what "pass by value" does. It makes a copy of the variable so that the function uses a copy rather than the original

Functions that can change their caller's variables use "pass by reference", which means they take a reference to the caller's variable instead of a copy. You'll learn how to make one of these functions later, but for this exercise you only need to know that if a function alters your variable then you have to pass the variables with & like this:

var a int
err := fmt.Scan(&a)

When you write &a instead of a you are telling Go to give that function direct access to your a variable in main() so it can change it. That's how we'll prompt the user for an int, or anything else.

Later you'll learn how to make your own functions like fmt.Scan() using pointers and references like this.

Introducing fmt.Scan

The fmt.Scan function is documented in Go's fmt packages docs but the documentation is very sparse. There is also a fmt.Scanln() variant that works slightly differently, but does NOT scan a line as you would imagine a function named "SCAN LINE" would.

How these work is:

  1. It takes each parameter you pass and looks that their types.
  2. For each variable, it tries to read the terminal input for characters that match the type's format. That means if you fmt.Scan on a variable that's an int then it reads only numbers. Scan a float and it'll do numbers and . (period).
  3. It stops reading the text for that variable at the first space character, stores it into the reference, and then moves to the next variable.
  4. After it's read everything you've listed it returns the number of items in your list it scanned, and/or an error. This is key, because if you give it 4 items and it only scans 3 then you have bad input or need to scan for more. Also if you get an error you need to handle that as well.

The difference between fmt.Scan() and fmt.Scanln() is that Scan considers newlines (the ENTER key) whitespace, and Scanln considers it an end of input indicator. That means if you have to read exactly 3 thing then a newline then Scanln is better. In practice they mostly work the same but try one or the other when either isn't working for you.

The Code

WARNING WARNING I have included an error in this code on purpose. Try to figure out what I did wrong by reading the documentation for fmt.Scan() and using what you know about function calls.

View Source file ex14/main.go Only

package main

import (
    "fmt"
)

func main() {
    // need to declare variables first to make space for them
    var age int
    var name string
    var favorite string

    // REMEMBER: this has an erorr, fix it
    fmt.Print("What's your name? ")
    fmt.Scan(&name)

    fmt.Print("How old are you? ")
    fmt.Scan(&age)

    fmt.Print("What's your favorite kind of pet? ")
    fmt.Scan(&favorite)

    fmt.Println("You're name is", name)
    fmt.Println("You are", age, "years old")
    fmt.Println("You're favorite pet is", favorite)
}

The Breakdown

After these lines there's your usual fmt.Println to print out the results.

The Practice

  1. Fix It -- This code is already broken so you should fix it instead.
  2. Change It -- Try using fmt.Scanln instead. Add more questions and answers. Maybe create a little calculator.
  3. Remake It -- As usual, write a description the recreate it from memory using the description. The more you do this, the better you'll get.

Study Drills

  1. Read about the other ways you can get input from the user in the fmt library docs.
  2. Try to use as many as you can figure out.
Previous Lesson Next Lesson

Register for Learn Go the Hard Way

Register today for the course and get the all currently available videos and lessons, plus all future modules for no extra charge.