let value = 5;
if value < 10 {
println!("Value is under 10");
} else if value == 10 {
println!("Value is 10");
} else {
println!("Value is over 10");
}
if / else
let value = 5;
if value {
println!("Value is not zero");
}
condition must be boolean
let name = "Mary";
if name == "Bob" || name == "Bryan" {
println!("Name starts with a B!");
} else if name != "Ben" && !(name == "Jerry") {
println!("Is not Ben or Jerry");
}
Boolean operators
let number = -14;
let is_positive = if number >= 0 {true} else {false};
println!("is_positive: {}", is_positive);
Variable binding
let mut count: u64 = 0;
loop {
count += 1;
if count > 1000000 {break}
}
println!("count: {}", count);
loop
let mut count: u64 = 0;
let count = loop {
count += 1;
if count > 1000000 {break count}
};
println!("count: {}", count);
returning values from loop
'outer: loop {
while true {
break 'outer;
}
}
loop labels
let mut cond = true;
while cond {
cond = !cond;
}
println!("{}", cond);
while
let arr = [1,2,3];
for el in arr {
println!("{}", el*2);
}
for i in 0..10 {
println!("{}", i);
}
for
match SCRUTINEE {
PATTERN => EXPRESSION,
PATTERN => {
EXPRESSION BLOCK
}
}
let a = 1;
match a {
1 => println!("One"),
2 => println!("Two"),
i32::MIN..=i32::MAX => println!("Neither one nor two"),
}
// is equivalent to
if a == 1 {
println!("One");
} else if a == 2 {
println!("Two")
} else {
println!("Neither one nor two");
}
Example
let a = 1;
match a {
1 => println!("One"),
2 => println!("Two"),
}
match is exhaustive!
let a = 1;
match a {
1 => println!("One"),
2 => println!("Two"),
i32::MIN..=i32::MAX => println!("Neither one nor two")
}
let a = 1;
match a {
1 => println!("One"),
2 => println!("Two"),
_ => println!("Neither one nor two")
}
let a = 1;
match a {
1 => println!("One"),
2 => println!("Two"),
.. => println!("Neither one nor two")
}
let a = 51;
match a {
1 => println!("One"),
2 => println!("Two"),
n => println!("Neither one nor two, but {}", n)
}
matching named variables
let a = 51;
match a {
1 => println!("One"),
2 => println!("Two"),
_ => println!("Neither one nor two, but {}", a)
}
why not just print a directly?
let a = 51;
match a + 1 {
1 => println!("One"),
2 => println!("Two"),
n => println!("Neither one nor two, but {}", n)
}
let a = 51;
match a + 1 {
1 => println!("One"),
2 => println!("Two"),
n => println!("Neither one nor two, but {}", n)
}
// is equivalent to
if a + 1 == 1 {
println!("One");
} else if a + 1 == 2 {
println!("Two");
} else {
println!("Neither one nor two, but {}", a + 1);
}
let a = 51;
match a {
1..5 => println!("one to four"),
5..=10 => println!("five to ten"),
1 | 2 | 3 | 4 => unreachable!(),
_ => println!("Anything else")
}
ranges, logical operators
match 3 {
1..=10 => println!("Between 1 and 10, but don't know exactly"),
_ => ()
}
match 3 {
n @ 1..=10 => println!("{} is between 1 and 10", n),
_ => ()
}
variable binding with @
match 3 {
1..=10 => println!("Between 1 and 10, but don't know exactly"),
_ => ()
}
match 3 {
n @ 1..=10 => println!("{} is between 1 and 10", n),
_ => ()
}
match 3 {
n if n >= 0 => println!("Positive number"),
n if n < 0 => println!("Negative number")
}
match guards
match 3 {
n if n >= 0 => println!("Positive number"),
n if n < 0 => println!("Negative number"),
_ => ()
}
match 3 {
n if n >= 0 => println!("Positive number"),
n if n < 0 => println!("Negative number"),
_ => unreachable!()
}
let rgb = (255, 255, 255);
match rgb {
(255, _, _) => println!("Max red!"),
(_r, 255, _b) => println!("Max green!"),
(0, 0, b) => println!("Only blue, brightness: {:.2}", b as f64 / 255 as f64),
(r, g, b) => println!("r: {}, g: {}, b: {}", r, g, b),
}
Destructuring
// result from a video game speedrun attempt
enum SpeedRunResult {
Failed,
Aborted{
seconds: f64,
reason: String
},
Finished(f64),
}
match result {
SpeedRunResult::Failed => println!("Game over!"),
SpeedRunResult::Aborted{seconds: s, reason: r} => println!("Aborted at {}s because {}", s, r),
SpeedRunResult::Finished(seconds) => println!("{}s is an excellent time!", seconds),
}
Matching enums
// result from a video game speedrun attempt
enum SpeedRunResult {
Failed,
Aborted{
seconds: f64,
reason: String
},
Finished(f64),
}
let result = SpeedRunResult::Aborted{
seconds: 134.42,
reason: String::from("failed to jump over the koopa")
};
match result {
SpeedRunResult::Failed => println!("Game over!"),
SpeedRunResult::Aborted{seconds: s, reason: r} => println!("Aborted at {}s because {}", s, r),
SpeedRunResult::Finished(seconds) => println!("{}s is an excellent time!", seconds),
}
Matching enums
let rgb = (255, 255, 255);
if let (255, _, _) = rgb {
println!("Max red!");
}
// is equivalent to
match rgb {
(255, _, _) => println!("Max red!"),
_ => (),
}
while let Pattern = Scrutinee {
BlockExpression
}
let rgb = (255, 255, 255);
if let (255, _, _) = rgb {
println!("Max red!");
} else {
println!("Not max red..");
}
// is equivalent to
match rgb {
(255, _, _) => println!("Max red!"),
_ => println!("Not max red..")
}
else can be used with if let
while let Pattern = Scrutinee {
BlockExpression
}
while let
fn is_divisible_by(val: i64, div: i64) -> bool {
val / div == 2
}
let mut a = 1;
while let false = is_divisible_by(a, 7) {
a += 1;
}
println!("{}", a);
fn main() {
panic!("Best program ever");
}
fn main() {
let _var = true || panic!("Best program ever");
}
fn main() {
let _var = true && panic!("Best program ever");
}
enum Result<T, E> {
Ok(T),
Err(E),
}
use std::fs::File;
fn main() {
let f = File::open("rust_workshop_notes.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Could not open file: {:?}", error),
};
}
use std::fs::File;
fn main() {
let f = File::open("rust_workshop_notes.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Could not open file: {:?}", error),
};
}
use std::fs::File;
fn main() {
let f = File::open("rust_workshop_notes.txt").unwrap();
/*let f = match f {
Ok(file) => file,
Err(error) => panic!("Could not open file: {:?}", error),
};*/
}
use std::fs::File;
fn main() {
let f = File::open("rust_workshop_notes.txt").expect("Could not open file");
/*let f = match f {
Ok(file) => file,
Err(error) => panic!("Could not open file: {:?}", error),
};*/
}
fn main() {
let num_str = "one";
let fallback_num = 0;
let num: i32 = num_str.parse().unwrap_or(fallback_num);
println!("{}", num);
}
use std::num::ParseIntError;
type Point = (i32, i32);
fn parse_coordinate(x: &str, y: &str) -> Result<Point, ParseIntError> {
Ok( (x.parse::<i32>()?, y.parse::<i32>()?) )
}
fn main() {
let parsed: Point = parse_coordinate("1", "2").unwrap();
println!("{:?}", parsed);
}
use std::num::ParseIntError;
type Point = (i32, i32);
fn parse_coordinate(x: &str, y: &str) -> Result<Point, ParseIntError> {
Ok( (x.parse::<i32>()?, y.parse::<i32>()?) )
}
fn main() {
let parsed: Point = parse_coordinate("one", "two").unwrap();
println!("{:?}", parsed);
}
use std::num::ParseIntError;
type Point = (i32, i32);
type ParseResult<T> = Result<T, ParseIntError>;
fn parse_coordinate(x: &str, y: &str) -> ParseResult<Point> {
Ok( (x.parse::<i32>()?, y.parse::<i32>()?) )
}
fn main() {
let parsed: Point = parse_coordinate("one", "two").unwrap();
println!("{:?}", parsed);
}
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> {
match s.parse::<i32>() {
Ok(i) => Ok(i*2),
Err(e) => Err(e)
}
}
fn parse_and_double_2(s: &str) -> Result<i32, ParseIntError> {
Ok(s.parse::<i32>()? * 2)
}
fn main() {
println!("{:?}", parse_and_double("2"));
println!("{:?}", parse_and_double_2("2"));
println!("{:?}", parse_and_double_2("house"));
println!("{:?}", parse_and_double_2("2").unwrap());
}
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> {
let res = match s.parse::<i32>() {
Ok(i) => Ok(i*2),
Err(e) => Err(e)
};
println!("Inside parse_and_double: {:?}", res);
res
}
fn parse_and_double_2(s: &str) -> Result<i32, ParseIntError> {
let res = Ok(s.parse::<i32>()? * 2);
println!("Inside parse_and_double_2: {:?}", res);
res
}
fn main() {
parse_and_double("2");
parse_and_double_2("2");
parse_and_double("house");
parse_and_double_2("house");
}
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> {
let res = match s.parse::<i32>() {
Ok(i) => Ok(i*2),
Err(e) => Err(e)
};
println!("Inside parse_and_double: {:?}", res);
res
}
fn parse_and_double_2(s: &str) -> Result<i32, ParseIntError> {
let res = Ok(s.parse::<i32>()? * 2);
println!("Inside parse_and_double_2: {:?}", res);
res
}
fn main() {
parse_and_double("2");
parse_and_double_2("2");
parse_and_double("house");
parse_and_double_2("house");
}
use std::num::ParseIntError;
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> {
let res = match s.parse::<i32>() {
Ok(i) => i,
Err(e) => return Err(e)
};
let res = Ok(res*2);
println!("Inside parse_and_double: {:?}", res);
res
}
fn parse_and_double_2(s: &str) -> Result<i32, ParseIntError> {
let res = s.parse::<i32>()?;
let res = Ok(res*2);
println!("Inside parse_and_double_2: {:?}", res);
res
}
fn main() {
parse_and_double("2");
parse_and_double_2("2");
parse_and_double("house");
parse_and_double_2("house");
}
#[derive(PartialEq, Debug)]
enum ParseOrDoubleError {
ParseIntError,
DivideByZero,
}
fn parse_and_divide(s: &str) -> Result<i32, ParseOrDoubleError> {
let i = s.parse::<i32>();
match i {
Err(_e) => Err(ParseOrDoubleError::ParseIntError),
Ok(0) => Err(ParseOrDoubleError::DivideByZero),
Ok(non_zero) => Ok(1000 / non_zero)
}
}
fn main() {
println!("2: {:?}", parse_and_divide("2"));
println!("2: {:?}", parse_and_divide("0"));
println!("2: {:?}", parse_and_divide("house"));
}
use std::fs::File;
use std::error::Error; // Error is a Trait
fn parse_and_open(number: &str, filepath: &str) -> Result<(), Box<dyn Error>> {
number.parse::<i32>()?;
File::open(filepath)?;
Ok(())
}
fn main() {
println!("{:?}", parse_and_open("2", "rust_workshop_notes.txt"));
println!("{:?}", parse_and_open("two", "rust_workshop_notes.txt"));
}
https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/define_error_type.html
use std::fmt;
use std::error::Error;
#[derive(Debug, Clone)]
struct DivideByZeroError;
impl Error for DivideByZeroError {}
impl fmt::Display for DivideByZeroError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "divide by zero error")
}
}
fn parse_and_divide(s: &str) -> Result<i32, Box<dyn Error>> {
let i = s.parse::<i32>()?;
match i {
0 => Err(Box::new(DivideByZeroError)),
non_zero => Ok(1000 / non_zero)
}
}
fn main() {
println!("2: {:?}", parse_and_divide("2"));
println!("2: {:?}", parse_and_divide("0"));
println!("2: {:?}", parse_and_divide("house"));
}
use std::fmt;
use std::error::Error;
#[derive(Debug, Clone)]
struct DivideByZeroError;
impl Error for DivideByZeroError {}
impl fmt::Display for DivideByZeroError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "divide by zero error")
}
}
fn parse_and_divide(s: &str) -> Result<i32, Box<dyn Error>> {
let i = s.parse::<i32>()?;
match i {
0 => Err(Box::new(DivideByZeroError)),
non_zero => Ok(1000 / non_zero)
}
}
fn main() {
println!("2: {:?}", parse_and_divide("2"));
println!("2: {:?}", parse_and_divide("0"));
println!("2: {:?}", parse_and_divide("house"));
}
use anyhow::Error;
fn read_number_file(path: &str) -> Result<u32, Error> {
let string = std::fs::read_to_string(path)?;
let number = string.parse()?;
Ok(number)
}
fn main() {
let number = read_number_file("my_number.txt").unwrap();
println!("Number from file: {}", number);
}
enum Option<T> {
Some(T),
None,
}
Rust | C++ |
---|---|
return None; | return std::nullopt; |
return Some(foo); | return foo; |
is_some() | operator bool() has_value() |
unwrap() | value() |
unwrap_or(bar) | value_or(bar) |
struct Satelite {
distance_from_earth: Option<u32>
}
fn main() {
let sat = Satelite{distance_from_earth: Some(400)};
let in_orbit = match sat.distance_from_earth {
Some(d) if d <= 22_223 => true,
_ => false
};
println!("In orbit: {}", in_orbit);
}
struct Satelite {
distance_from_earth: Option<u32>
}
fn main() {
let sat = Satelite{distance_from_earth: Some(400)};
let in_orbit = sat.distance_from_earth.unwrap() <= 22_223;
println!("In orbit: {}", in_orbit);
}
struct Satelite {
distance_from_earth: Option<u32>
}
fn main() {
let sat = Satelite{distance_from_earth: None};
let in_orbit = sat.distance_from_earth.expect("Distance unknown") <= 22_223;
println!("In orbit: {}", in_orbit);
}
fn adds_five(number: Option<u8>) -> Option<u8> {
Some(number?.saturating_add(5))
}
fn main() {
let n: Option<u8> = Some(253);
let n = adds_five(n).unwrap();
println!("{:?}", n);
}
fn adds_five(number: Option<u8>) -> Option<u8> {
Some(number?.saturating_add(5))
}
fn main() {
let n: Option<u8> = None;
let n = adds_five(n).unwrap();
println!("{:?}", n);
}
use std::fs::File;
fn main() {
let f = File::open("rust_workshop_notes.txt");
println!("f is_ok: {}", f.is_ok());
println!("f is_err: {}", f.is_err());
let option = f.ok();
println!("option: {:?}", option);
println!("option is_some: {}", option.is_some());
println!("option is_none: {}", option.is_none());
}
// use std::fs::File;
fn main() {
// let f = File::open("rust_workshop_notes.txt");
let f: Result<&str, &str> = Ok("some data");
println!("f is_ok: {}", f.is_ok());
println!("f is_err: {}", f.is_err());
let option = f.ok();
println!("option: {:?}", option);
println!("option is_some: {}", option.is_some());
println!("option is_none: {}", option.is_none());
}
use std::num::ParseIntError;
type Point = (i32, i32);
fn parse_coordinate(x: &str, y: &str) -> Result<Point, ParseIntError> {
Ok( (x.parse::<i32>()?, y.parse::<i32>()?) )
}
fn main() {
let parsed: Point = parse_coordinate("1", "2").unwrap();
println!("{:?}", parsed);
}
Refactor parse_coordinate to return Option instead of Result
type Point = (i32, i32);
fn parse_coordinate(x: &str, y: &str) -> Option<Point> {
Some( (x.parse::<i32>().ok()?, y.parse::<i32>().ok()?) )
}
fn main() {
let parsed: Point = parse_coordinate("1", "2").unwrap();
println!("{:?}", parsed);
}
Refactor parse_coordinate to return Option instead of Result