Added chapter 8

This commit is contained in:
2020-06-11 18:01:30 -04:00
parent 1e76dc4a17
commit 933ff6d190
18 changed files with 525 additions and 1 deletions

7
src/FlowOfControl.rs Normal file
View File

@@ -0,0 +1,7 @@
pub mod IfElse;
pub mod Loop;
pub mod While;
pub mod ForAndRange;
pub mod Match;
pub mod IfLet;
pub mod WhileLet;

View File

@@ -0,0 +1,60 @@
pub fn main(){
//`n` will take the values: 1, 2, ..., 100 in each iteration
for n in 1..101{
if((n % 15) == 0){
println!("fizzbuzz");
}
else if((n % 3) == 0){
println!("fizz");
}
else if((n % 5) == 0){
println!("buzz");
}
else{
println!("{}", n);
}
}
// `n` will take the values: 1, 2, ..., 100 in each iteration
for n in 1..=100{
if((n % 15) == 0){
println!("fizzbuzz");
}
else if((n % 3) == 0){
println!("fizz");
}
else if((n % 5) == 0){
println!("buzz");
}
else{
println!("{}", n);
}
}
//This borrows each element of the collection through each iteration. Thus leaving the collection untouched and available for reuse after the loop.
let names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter(){
match name {
&"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
}
//This consumes the collection so that on each iteration the exact data is provided.
//Once the collection has been consumed it is no longer available for reuse as it has been 'moved' within the loop.
for name in names.into_iter(){
match name{
"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
}
//This mutably borrows each element of the collection, allowing for the collection to be modified in place.
let mut mutNames = vec!["Bob", "Frank", "Ferris"];
for name in mutNames.iter_mut(){
*name = match name{
&mut "Ferris" => "There is a rustacean among us!",
_ => "Hello",
}
}
println!("mutNames: {:?}", mutNames);
}

View File

@@ -0,0 +1,31 @@
pub fn main(){
let n = 5;
if(n < 0){
print!("{} is negative", n);
}
else if(n > 0){
print!("{} is positive", n);
}
else{
print!("{} is zero", n);
}
let big_n =
if((n < 10) && (n > -10)){
println!(", and is a small number, increase ten-fold");
// This expression returns an `i32`.
10 * n
}
else{
println!(", and is a big number, halve the number");
// This expression must return an `i32` as well.
n / 2
// TODO ^ Try suppressing this expression with a semicolon.
};
// ^ Don't forget to put a semicolon here! All `let` bindings need it.
println!("{} -> {}", n, big_n);
}

View File

@@ -0,0 +1,86 @@
// Our example enum
enum Foo{
Bar,
Baz,
Qux(u32)
}
//This enum purposely neither implements nor derives PartialEq.
//That is why comparing Foo::Bar == a fails below.
/*
enum Foo {Bar}
fn main(){
let a = Foo::Bar;
//Variable a matches Foo::Bar
if Foo::Bar == a {
// ^-- this causes a compile-time error. Use `if let` instead.
println!("a is foobar");
}
}
*/
pub fn main(){
//All have type `Option<i32>`
let number = Some(7);
let letter: Option<i32> = None;
let emoticon: Option<i32> = None;
//The `if let` construct reads: "if `let` destructures `number` into
//`Some(i)`, evaluate the block (`{}`).
if let Some(i) = number{
println!("Matched {:?}!", i);
}
//If you need to specify a failure, use an else:
if let Some(i) = letter{
println!("Matched {:?}!", i);
}
else{
//Destructure failed. Change to the failure case.
println!("Didn't match a number. Let's go with a letter!");
}
//Provide an altered failing condition.
let i_like_letters = false;
if let Some(i) = emoticon{
println!("Matched {:?}!", i);
//Destructure failed. Evaluate an `else if` condition to see if the alternate failure branch should be taken:
}
else if i_like_letters{
println!("Didn't match a number. Let's go with a letter!");
}
else{
// The condition evaluated false. This branch is the default:
println!("I don't like letters. Let's go with an emoticon :)!");
}
//Create example variables
let a = Foo::Bar;
let b = Foo::Baz;
let c = Foo::Qux(100);
//Variable a matches Foo::Bar
if let Foo::Bar = a{
println!("a is foobar");
}
//Variable b does not match Foo::Bar
//So this will print nothing
if let Foo::Bar = b{
println!("b is foobar");
}
//Variable c matches Foo::Qux which has a value
//Similar to Some() in the previous example
if let Foo::Qux(value) = c{
println!("c is {}", value);
}
//Binding also works with `if let`
#[allow(unused_variables)]
if let Foo::Qux(value @ 100) = c{
println!("c is one hundred");
}
}

29
src/FlowOfControl/Loop.rs Normal file
View File

@@ -0,0 +1,29 @@
pub mod NestingAndLabels;
pub mod ReturningFromLoops;
pub fn main(){
let mut count = 0u32;
println!("Let's count until infinity!");
//Infinite loop
loop{
count += 1;
if(count == 3){
println!("three");
//Skip the rest of this iteration
continue;
}
println!("{}", count);
if(count == 5){
println!("OK, that's enough");
//Exit this loop
break;
}
}
}

View File

@@ -0,0 +1,22 @@
#[allow(unreachable_code)]
#[allow(unused_labels)]
pub fn main(){
'outer: loop{
println!("Entered the outer loop");
'inner: loop{
println!("Entered the inner loop");
//This would break only the inner loop break;
//This breaks the outer loop
break 'outer;
}
println!("This point will never be reached");
}
println!("Exited the outer loop");
}

View File

@@ -0,0 +1,13 @@
pub fn main(){
let mut counter = 0;
let result = loop{
counter += 1;
if(counter == 10){
break counter * 2;
}
};
assert_eq!(result, 20);
}

View File

@@ -0,0 +1,31 @@
pub mod Destructuring;
pub mod Guards;
pub mod Binding;
pub fn main() {
let number = 13;
//TODO ^ Try different values for `number`
println!("Tell me about {}", number);
match number{
//Match a single value
1 => println!("One!"),
//Match several values
2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
//Match an inclusive range
13..=19 => println!("A teen"),
//Handle the rest of cases
_ => println!("Ain't special"),
}
let boolean = true;
//Match is an expression too
let binary = match boolean {
//The arms of a match must cover all the possible values
false => 0,
true => 1,
//TODO ^ Try commenting out one of these arms
};
println!("{} -> {}", boolean, binary);
}

View File

@@ -0,0 +1,33 @@
// A function `age` which returns a `u32`.
fn age() -> u32{
15
}
fn some_number() -> Option<u32>{
Some(42)
}
pub fn main(){
println!("Tell me what type of person you are");
match age(){
0 => println!("I'm not born yet I guess"),
//Could `match` 1 ..= 12 directly but then what age
//would the child be? Instead, bind to `n` for the
//sequence of 1 ..= 12. Now the age can be reported.
n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
//Nothing bound. Return the result.
n => println!("I'm an old person of age {:?}", n),
}
match some_number() {
// Got `Some` variant, match if its value, bound to `n`,
// is equal to 42.
Some(n @ 42) => println!("The Answer: {}!", n),
// Match any other number.
Some(n) => println!("Not interesting... {}", n),
// Match anything else (`None` variant).
_ => (),
}
}

View File

@@ -0,0 +1,4 @@
pub mod Tuples;
pub mod Enums;
pub mod PointersRef;
pub mod Structs;

View File

@@ -0,0 +1,39 @@
//`allow` required to silence warnings because only one variant is used.
#[allow(dead_code)]
enum Color{
// These 3 are specified solely by their name.
Red,
Blue,
Green,
// These likewise tie `u32` tuples to different names: color models.
RGB(u32, u32, u32),
HSV(u32, u32, u32),
HSL(u32, u32, u32),
CMY(u32, u32, u32),
CMYK(u32, u32, u32, u32),
}
pub fn main(){
let color = Color::RGB(122, 17, 40);
//TODO ^ Try different variants for `color`
println!("What color is it?");
//An `enum` can be destructured using a `match`.
match color {
Color::Red => println!("The color is Red!"),
Color::Blue => println!("The color is Blue!"),
Color::Green => println!("The color is Green!"),
Color::RGB(r, g, b) =>
println!("Red: {}, green: {}, and blue: {}!", r, g, b),
Color::HSV(h, s, v) =>
println!("Hue: {}, saturation: {}, value: {}!", h, s, v),
Color::HSL(h, s, l) =>
println!("Hue: {}, saturation: {}, lightness: {}!", h, s, l),
Color::CMY(c, m, y) =>
println!("Cyan: {}, magenta: {}, yellow: {}!", c, m, y),
Color::CMYK(c, m, y, k) =>
println!("Cyan: {}, magenta: {}, yellow: {}, key (black): {}!",
c, m, y, k),
//Don't need another arm because all variants have been examined
}
}

View File

@@ -0,0 +1,43 @@
pub fn main(){
//Assign a reference of type `i32`. The `&` signifies there is a reference being assigned.
let reference = &4;
match reference{
//If `reference` is pattern matched against `&val`, it results in a comparison like:
//`&i32`
//`&val`
//^ We see that if the matching `&`s are dropped, then the `i32` should be assigned to `val`.
&val => println!("Got a value via destructuring: {:?}", val),
}
//To avoid the `&`, you dereference before matching.
match *reference{
val => println!("Got a value via dereferencing: {:?}", val),
}
//What if you don't start with a reference? `reference` was a `&`
//because the right side was already a reference. This is not a reference because the right side is not one.
let _not_a_reference = 3;
// Rust provides `ref` for exactly this purpose. It modifies the
// assignment so that a reference is created for the element; this reference is assigned.
let ref _is_a_reference = 3;
// Accordingly, by defining 2 values without references, references can be retrieved via `ref` and `ref mut`.
let value = 5;
let mut mut_value = 6;
//Use `ref` keyword to create a reference.
match value{
ref r => println!("Got a reference to a value: {:?}", r),
}
//Use `ref mut` similarly.
match mut_value{
ref mut m => {
// Got a reference. Gotta dereference it before we can add anything to it.
*m += 10;
println!("We added 10. `mut_value`: {:?}", m);
},
}
}

View File

@@ -0,0 +1,22 @@
pub fn main(){
struct Foo{
x: (u32, u32),
y: u32,
}
// Try changing the values in the struct to see what happens
let foo = Foo { x: (1, 2), y: 3 };
match foo{
Foo { x: (1, b), y } => println!("First of x is 1, b = {}, y = {} ", b, y),
// you can destructure structs and rename the variables,
// the order is not important
Foo { y: 2, x: i } => println!("y is 2, i = {:?}", i),
// and you can also ignore some variables:
Foo { y, .. } => println!("y = {}, we don't care about x", y),
// this will give an error: pattern does not mention field `x`
//Foo { y } => println!("y = {}", y);
}
}

View File

@@ -0,0 +1,14 @@
pub fn main(){
let pair = (0, -2);
//TODO ^ Try different values for `pair`
println!("Tell me about {:?}", pair);
//Match can be used to destructure a tuple
match pair{
//Destructure the second
(0, y) => println!("First is `0` and `y` is `{:?}`", y),
(x, 0) => println!("`x` is `{:?}` and last is `0`", x),
_ => println!("It doesn't matter what they are"),
//`_` means don't bind the value to a variable
}
}

View File

@@ -0,0 +1,13 @@
pub fn main(){
let pair = (2, -2);
//TODO ^ Try different values for `pair`
println!("Tell me about {:?}", pair);
match pair{
(x, y) if x == y => println!("These are twins"),
//The ^ `if condition` part is a guard
(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
(x, _) if x % 2 == 1 => println!("The first one is odd"),
_ => println!("No correlation..."),
}
}

View File

@@ -0,0 +1,23 @@
pub fn main(){
//A counter variable
let mut n = 1;
//Loop while `n` is less than 101
while n < 101 {
if(n % 15 == 0){
println!("fizzbuzz");
}
else if(n % 3 == 0){
println!("fizz");
}
else if(n % 5 == 0){
println!("buzz");
}
else{
println!("{}", n);
}
//Increment counter
n += 1;
}
}

View File

@@ -0,0 +1,19 @@
pub fn main(){
// Make `optional` of type `Option<i32>`
let mut optional = Some(0);
//This reads: "while `let` destructures `optional` into
//`Some(i)`, evaluate the block (`{}`). Else `break`.
while let Some(i) = optional{
if(i > 9){
println!("Greater than 9, quit!");
optional = None;
}
else{
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i + 1);
}
//^ Less rightward drift and doesn't require explicitly handling the failing case.
}
//^ `if let` had additional optional `else`/`else if` clauses. `while let` does not have these.
}

View File

@@ -1,5 +1,6 @@
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(unused_parens)]
mod HelloWorld;
mod Primitives;
@@ -8,6 +9,7 @@ mod VariableBindings;
mod Types;
mod Conversion;
mod Expressions;
mod FlowOfControl;
fn main(){
@@ -77,5 +79,38 @@ fn main(){
//Conversion::ToAndFromStrings::main();
//7 Expressions
Expressions::main();
//Expressions::main();
//8 Flow of Control
//8.1 if/else
FlowOfControl::IfElse::main();
//8.2 loop
FlowOfControl::Loop::main();
//8.2.1 Nesting and labels
FlowOfControl::Loop::NestingAndLabels::main();
//8.2.2 Returning from loops
FlowOfControl::Loop::ReturningFromLoops::main();
//8.3 while
FlowOfControl::While::main();
//8.4 for and range
FlowOfControl::ForAndRange::main();
//8.5 match
FlowOfControl::Match::main();
//8.5.1 Destructuring
//8.5.1.1 tuples
FlowOfControl::Match::Destructuring::Tuples::main();
//8.5.1.2 enums
FlowOfControl::Match::Destructuring::Enums::main();
//8.5.1.3 pointers/ref
FlowOfControl::Match::Destructuring::PointersRef::main();
//8.5.1.4 structs
FlowOfControl::Match::Destructuring::Structs::main();
//8.5.2 Guards
FlowOfControl::Match::Guards::main();
//8.5.3 Binding
FlowOfControl::Match::Binding::main();
//8.6 if let
FlowOfControl::IfLet::main();
//8.7 while let
FlowOfControl::WhileLet::main();
}