CodeRigor

LESSON

Read what the user types

Ask a question, read the line the user types with a scanner, turn text into a number with strconv.Atoi, check the error value and build programs that prompt, read, compute and print.

Every program so far knew all its values before it started. An interactive program asks the person using it (the user) for information while it runs, and its output depends on the answers. This lesson shows how a Go program reads what the user types.

Reading one line

Here is a complete program that asks for a name and greets the person. It is shown without a run button, for a reason explained in the next section.

Go
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)

    fmt.Print("What is your name? ")
    scanner.Scan()
    name := scanner.Text()

    fmt.Println("Hello, " + name + "!")
}

If the user types Ada and presses Enter, the whole session looks like this:

Text
What is your name? Ada
Hello, Ada!

Five things are new.

Several imports. When a program needs more than one package, the names go in round brackets after import, one per line.

Standard input. The text a user types arrives at the program through a channel called standard input. In Go its name is os.Stdin, from the package os (short for "operating system").

A scanner. bufio.NewScanner(os.Stdin) creates a scanner: a tool that hands standard input to your program one line at a time. The line scanner := bufio.NewScanner(os.Stdin) stores it in a variable. Write this line once, at the top of main.

Reading a line takes two steps. scanner.Scan() waits until the user has typed a line and pressed Enter. scanner.Text() then gives you that line as a string, without the Enter. The dot means "ask this scanner to do something".

A prompt. fmt.Print is fmt.Println without the line ending. Because the line is not ended, the user's answer appears on the same line as the question. A question printed this way is called a prompt. Put a space at the end of it, so the answer does not touch the question mark.

Go also has a shorter-looking tool, fmt.Scan, but it stops at the first space, so Ada Lovelace would arrive as Ada. A scanner reads the whole line, so this unit uses it everywhere.

Running programs that read input

The examples on this page that read input have no run button, because a page cannot stop and wait for you to type. To run one, copy it into the playground, type the user's answers into the Standard input box, one answer per line, and press run.

One difference from a real terminal: the playground gives your program the typed lines without showing them, so the output there reads What is your name? Hello, Ada!. In a terminal on your own computer, and in the sessions shown in these lessons, what the user types appears after the prompt.

What you read is always text

scanner.Text() always gives a string, even when the user types digits. If the user types 12, you get the string "12": two characters, not the number twelve. Go does not do arithmetic with text. This program is refused by the compiler:

Go
package main

import "fmt"

func main() {
    typed := "12"
    fmt.Println(typed + 1)
}
Text
# command-line-arguments
./main.go:7:17: invalid operation: typed + 1 (mismatched types string and untyped int)

The message says that typed is a string and 1 is a whole number, and that the two cannot be added.

Turn text into a number

The package strconv (short for "string conversion") turns text into numbers. Its tool strconv.Atoi takes a string and gives back the whole number written in it.

There is a catch, and Go makes you face it straight away. The conversion can fail: twelve and 12 apples are not whole numbers. So strconv.Atoi gives back two values at once: the number, and an error value that says whether the conversion worked. You receive them in two variables separated by a comma:

Go
number, err := strconv.Atoi(typed)

err is the usual name for an error value. When the conversion worked, err holds the special value nil, which is Go's word for "nothing": there is no error. When it failed, err holds a description of what went wrong.

Go refuses unused variables, so you cannot receive err and then ignore it. The standard thing to do is check it on the very next lines:

Go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    typed := "12"
    number, err := strconv.Atoi(typed)
    if err != nil {
        fmt.Println("Please type a whole number.")
        return
    }
    fmt.Println(number + 1)
}

This prints 13. Here typed := "12" stands in for a line the user typed, so that the example can run on the page.

Read the three lines that start with if as: "if err is not nothing, print a message and stop". != means "is not equal to", and return inside main ends the program at once. The next lesson explains if in full. For now, write these lines after every conversion, exactly as they are here.

Text in, number out
start / 4 ⇄ code
typed holds two characters. strconv.Atoi reads them and produces a separate whole number, plus an error value that is nil because the conversion worked.
Text in, number out
typed holds two characters. strconv.Atoi reads them and produces a separate whole number, plus an error value that is nil because the conversion worked.

Change "12" to "twelve" in the example and run it again. The conversion fails, err is no longer nil, and the program prints Please type a whole number. and stops. The last line never runs.

For a decimal number there is strconv.ParseFloat(typed, 64), used in the same way: it gives back a float64 and an error value.

The shape of an interactive program

Almost every small interactive program has the same shape: prompt, read, convert, compute, print.

Prompt, read, convert, compute, print
start / 6
The program asks, waits for a line, turns the text into a number, calculates and shows the result. If the text is not a number, it says so and stops.
Prompt, read, convert, compute, print
The program asks, waits for a line, turns the text into a number, calculates and shows the result. If the text is not a number, it says so and stops.

Here is the whole shape in one program:

Go
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)

    fmt.Print("What is your name? ")
    scanner.Scan()
    name := scanner.Text()

    fmt.Print("How old are you? ")
    scanner.Scan()
    age, err := strconv.Atoi(scanner.Text())
    if err != nil {
        fmt.Println("Please type a whole number.")
        return
    }

    fmt.Printf("Hello, %s!\n", name)
    fmt.Printf("Next year you will be %d.\n", age+1)
}

With the answers Ada and 36, the session is:

Text
What is your name? Ada
How old are you? 36
Hello, Ada!
Next year you will be 37.

With the answers Ada and quite old, the conversion fails and the session is:

Text
What is your name? Ada
How old are you? quite old
Please type a whole number.

The one scanner serves both questions: each scanner.Scan() waits for the next line. The name is used as text, so it is not converted. The age is used in arithmetic, so it is.

Try it in the playground with two lines in the Standard input box.

If the program asks for a line and there is none left (in the playground, when the Standard input box has too few lines), scanner.Text() gives an empty string. An empty string is not a number, so the conversion fails and the program prints its message and stops.

Three errors you will meet

Receiving only one value. strconv.Atoi gives back two values, and you must receive both.

Go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    typed := "12"
    number := strconv.Atoi(typed)
    fmt.Println(number + 1)
}
Text
# command-line-arguments
./main.go:10:15: assignment mismatch: 1 variable but strconv.Atoi returns 2 values

"Returns" means "gives back". Line 10 has one name on the left and two values arriving. Write number, err := strconv.Atoi(typed).

Receiving the error value and not checking it.

Go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    typed := "12"
    number, err := strconv.Atoi(typed)
    fmt.Println(number + 1)
}
Text
# command-line-arguments
./main.go:10:13: declared and not used: err

This is the unused-variable rule from the last lesson, doing useful work: it will not let you forget that the conversion might have failed. Add the if err != nil lines.

Using a package without importing it, or importing one without using it. Both stop the compiler. If you call strconv.Atoi without "strconv" in the import list, the message is undefined: strconv. If "strconv" is in the list and nothing uses it, the message is "strconv" imported and not used. The import list must match exactly the packages the program uses.

What you can do now

You can prompt for a line, read it with a scanner, turn text into a whole number, deal with text that is not a number, and build programs in the shape prompt, read, convert, compute, print. In the exercises you will predict what conversions produce, repair two faulty conversations and write one of your own.

Next: make decisions with if and else, so that a program can do different things for different answers.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Starts at 'Getting User Input' (45:18), two minutes: asking a question and reading the answer into a variable. The video reads with `fmt.Scan`, the shorter tool that stops at the first space; this lesson uses a scanner, which reads the whole line. The idea of prompt, then read, is the same.