Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
110: Scanning Input with fmt.Scan Family
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.
There are no comments for now.