Skip to Content
Course content

110: Scanning Input with fmt.Scan Family

Click on the "Edit" button in the top corner of the screen to edit your slide content.

How do I actually get a value from the terminal into a variable?

The most straightforward way to do this is with fmt.Scan. The key thing to remember—and where I see most people trip up early on—is that you have to pass a pointer to the variable. Go needs to know the memory address of where to store the input, not just a copy of the variable's current value.

package main

import "fmt"

func main() {
    var age int
    fmt.Print("Enter your age: ")
    
    // Note the '&' before age. Without it, the code won't compile
    // or won't actually update the variable.
    _, err := fmt.Scan(&age)
    if err != nil {
        fmt.Println("That wasn't a number!")
        return
    }
    fmt.Printf("You are %d years old.\n", age)
}

I usually ignore the return value (the number of items scanned) using the blank identifier _, but I always check the err. If a user types "twenty" when you're expecting an int, fmt.Scan will return an error, and your variable will remain at its zero value.

Why is my program skipping some of the input I type?

This happens because fmt.Scan and fmt.Scanln treat spaces as delimiters. They look for "tokens." If you're trying to capture a full name like "Jane Doe" into a single string variable, fmt.Scan will only grab "Jane" and leave "Doe" sitting in the input buffer. This often causes the next scan call in your program to trigger instantly with the leftover text, making it feel like the program is skipping lines.

If you need to capture a string that might contain spaces, fmt.Scan isn't your tool. You'd want to move over to the bufio package. But if you just need to grab a few separate words, you can just call Scan multiple times:

var firstName, lastName string
fmt.Print("Enter your full name: ")
fmt.Scan(&firstName, &lastName) 
// This works because it expects two separate tokens

What's the deal with Scanln and Scanf?

You'll see fmt.Scanln and fmt.Scanf in the wild. Scanln is almost identical to Scan, but it stops scanning as soon as it hits a newline. This is useful when you want to treat a line break as the end of the input sequence rather than letting it skip over to the next line to find the next piece of data.

Then there's Scanf. The "f" stands for "formatted." It's great when you expect the input to follow a very specific pattern, like a date or a coordinate. I use this when I want to enforce a structure without writing a bunch of custom parsing logic.

var x, y int
fmt.Print("Enter coordinates (x,y): ")
// This expects the user to actually type the comma
_, err := fmt.Scanf("(%d,%d)", &x, &y)
if err != nil {
    fmt.Println("Please use the (x,y) format!")
}

Just a heads-up: Scanf is a bit finicky. If the user puts a space where you didn't put one in the format string, it might fail. In my experience, unless you have a very strict format requirement, Scan or Scanln are much more forgiving.




📋 Practical Task

Build a Simple RPG Character Creator

Write a program that prompts a user to create a character for a game. Your program should:

  • Prompt for and scan a single-word Character Name (string).
  • Prompt for and scan a Strength score (int).
  • Prompt for and scan a Dexterity score (int).
  • Print a final summary line in the format: Character [Name] created with Stats: STR [Strength], DEX [Dexterity].

Challenge: Ensure that if the user enters a non-integer for the stats, the program prints an error message instead of crashing or printing a zero value.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.