Video Coming Soon...
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:
- It takes each parameter you pass and looks that their types.
- 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 anint
then it reads only numbers. Scan a float and it'll do numbers and.
(period). - 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.
- 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
// REMEMBER: this has an error, fix it
-- I told you. Did you fix it?fmt.Print("What's your name? ")
-- Print a prompt.fmt.Scan(&name)
-- Get the name.fmt.Print("How old are you? ")
-- Print the prompt.fmt.Scan(&age)
-- Get the age.fmt.Print("What's your favorite kind of pet? ")
-- Print the prompt.fmt.Scan(&favorite)
-- Get the favorite.
After these lines there's your usual fmt.Println
to print out the results.
The Practice
- Fix It -- This code is already broken so you should fix it instead.
- Change It -- Try using
fmt.Scanln
instead. Add more questions and answers. Maybe create a little calculator. - 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
- Read about the other ways you can get input from the user in the
fmt
library docs. - Try to use as many as you can figure out.
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.