✍️ Introduction
If you're just getting started with Rust, one of the first things you'll try is reading input from the user. Simple enough, right?
But then... Rust makes you create a string, pass it by mutable reference, and parse it into a number. Why all the steps? Why can’t we just write let age: i32 = stdin();
and call it a day?
By the end, you’ll have a solid grasp of how to read, parse, and safely handle user input in Rust.
Consider this code
use std::io;
fn main() {
println!("Enter a number:");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line");
// Trim whitespace and parse the string to an i32
let number: i32 = input.trim().parse().expect("Please type a number!");
println!("You entered: {}", number);
}
👇 What Happens Here:
read_line
reads user input into aString
.trim()
removes spaces and the newline character (\n
) from the input.parse()
converts the string to an integer.expect()
handles errors if the input isn't a valid number.
❗ If the input is invalid:
If the user types something like "hello"
instead of a number, parse()
will fail, and expect()
will show an error message.
🔍 Now, let's break down the line of code after the first print statement
let mut input = String::new();
✅ let
This is Rust's variable declaration keyword—it means "create a new variable." If you come from the JavaScript land, this must be familiar!
🔄 mut
This means the variable is mutable, or changeable. By default, Rust variables are immutable (unchangeable), so you need mut when you want to modify the variable later—like filling it with user input.
📦 input
This is the name of the variable. You can name it anything, but input is a descriptive name in this context.
🧵 String::new()
This creates a new empty String.
-
String
is scalable (growable) type in Rust. -
::new()
is an associated function that returns a new, emptyString
.
In other words, we are creating an empty container ready to be filled eventually. Now this piece of code stumped me!
io::stdin().read_line(&mut input).expect("Failed to read line");
What on earth is this?
let mut input = String::new();
only creates an empty string. It's like saying
Hey computer, get me a blank notepad (a mutable string) that I can write in later.
But at this point, the notepad is still blank—there’s no user input yet.
💬 So how do we get user input?
That’s what this part does:
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
Let's break this down. Shall we?
io::stdin()
: Accesses the standard input (your keyboard)read_line(&mut input)
: Reads a line of text from the user and puts
it into theinput
string just likescanf
in C.expect()
: If something goes wrong, expect an error and deliberately crash the program.
To summarize it, The first creates the storage and the second fills it with user input.
You're saying:
Try to read input. If it fails, don't continue—just stop and show this message.
🔍 Why not just accept a number directly?
Because when you type into a terminal or command line, you’re always sending text—even if it looks like a number.
For example: when you type 42
, the program receives as "42\n"
. So what you typed is text, not a number. Even "42"
is a string until you *convert *(or parse) it.
🧠 Why doesn’t Rust just handle that automatically?
Because Rust is very strict about types. It won’t assume what you meant—it makes you say it explicitly.
📌 Summary:
The terminal only gives you strings.
You must convert strings to numbers manually.
Rust does this on purpose for clarity, safety, and control.