Based on “The Rust Programming”
Programming a Guessing Game
rust has a few things that will be imported automatically into every rust program, called prelude
use
use
statment bring items into program that are not included inprelude
use
let
statement to create a variable;variables are immutable in rust by default, add
mut
before variable name::
inString::new()
indicatednew
is an function associated withString
type.if library
io
hasn’t been inported withuse std::io
at the beginning of the program, you could still use the function withstd::io::stdin
&
indicate this argument is a reference, which give you a way to let multiple parts of your code access one piece of data without needing to copy that data into memory multiple times.references are immutable like variable, write
&mut foo
instead of&foo
to make it mutable.we could written this code as:
io::stdin().read_line(&mut guess).expect("Failed to read line");
but this is more readable:
io::stdin() .read_line(&mut guess) .expect("Failed to read line");
read_line()
pass whatever user enters into it, also returns a value, this caseio::Result
.Result
types are enumerations(also enums, with a fixed set of possibility known as variants)Result
’s variants areOk
orErr
Ok
indicates the operation was successful, abd insideOk
is the generated valueErr
means the operation failed, and insideErr
contains the error log
io::Result
has anexpect
method you can call. if this instance ofio::Result
is anErr
,expect
will cause the program to crash and display the message to passed as an argument toexpect
without
expect
, program will still compile, but you will get a warningthe right way to suppress the warning is to actually write error handling, but in our case we will just crash the program when a program occurs.
crate is a collection of Rust source code files. the project we’ve been building is a binary crate, which is an executable.
the
rand
crate is a library crate, which contains code intended to be used in other programs, and can’t be executed on its own.change
Cargo.toml
to addrand
crate as a dependencyCargo understands *Sematic Versioning(SemVer, MAJOR.MINOR.PATCH, MAJOR when making incompatible API changes, MINOR when adding functionality in backwards compatible manner, PATCH when make backwards compatible bug fixes), the number
0.8.4
is actually shorthand for^0.8.4
, which mean any version that is at least0.8.4
, but below0.9.0
, Cargo considers these version to have public APIs compatible with version0.8.4
.then run
cargo build
to rebuild the project with added dependencies.Rust creates the
Cargo.lock
file the first time when you runcargo build
, Cargo will figures out all the versions of the dependencies that fit the criteria then save to it. When you build your project again in the future, cargo will see thatCargo.lock
exists, and will use these specifed version rather than figuring out versions again.This lets you have a reproducible build automatically, so crate
rand
will remain at0.8.4
until you explicitly upgrade itto upgdate a crate, run
cargo update
Ordering
is an enum, it has the variantsLess
,Greater
andEqual
.match
expression is made up of arms, an arm consists of pattern to natcg against, and the code that should be run if value given tomatch
fits that arm’s patterni32
, a 32-bit number;u32
, an unsigned 32-bit number;i64
, a 64-bit numbertrim
method on aString
instance will eliminate any whitespace at the beginning at endparse
method on strings parses a string into some kind of number, we need to tell Rust the exact number type we want by usinglet guess : u32
.parse
method might failed if charaters can’t logically converted into numbers, and it will returns aResult
type, like theread_line
methodloop
keyword creates an infinite loopbreak
keyword exit the loopOk(num) => num
just return thenum
thatparse
produced and put inside theOk
value._
inErr(_)
is a catchall value, in this case to match allErr
values.continue
keyword tells the program to go to the next iteration of theloop
.
Complete Code:
use std::io; // import I/O modules from Standard library
use std::cmp::Ordering;
use rand::Rng;
fn main()
{
println!("---Guess The Number---");
let secret = rand::thread_rng().gen_range(1..101);
println!("The secret number is: {}", secret);
loop //infinite loop
{
println!("Please input your guess:");
let mut guess = String::new(); // Create a mutable variable that is currently bound to a new, empty instance of a String
io::stdin() // Calling "stdin" function from "io" module
.read_line(&mut guess)
.expect("Failed to read line");
let guess : u32 = match guess.trim().parse() // Shadow the previous value of guess with this new one.
{
Ok(num) => num, // just return the num that parse produced
Err(_) => continue,
};
println!("Your guess: {}", guess); // The "{}" set of curly brackets is a placeholder, holdes the first value listed after the format string
match guess.cmp(&secret)
{
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal =>
{
println!("You win!");
break;
}
}
}
}