Rust 迴圈與流程控制
- 重點摘要
- if ... else if ... else
 - 三元運算 ( Ternary Operator)
 - 迴圈
- loop Loop: 無限迴圈,除非遇到 break
 - for Loop
 - while Loop
 
 - pattern matching: 類似其他語言的 switch/case 分支結構
 - if let: 若(if) 讓(let) matching condition 成真則做後續動作
 
 
if else
- condition 的部分可以省略括號,加上小括號的話 IDE 會出現移除的建議。
 - 與 Python 不同的是,Rust condition 必須是 boolean。(Python 非空字串集合等視為 True)
 
Rust if else example
    let x = 5;
    let y = 6;
    if x %2 ==0 && y %2 ==0 {
        println!("both even");
    }else if x %2 !=0 && y %2 !=0 {
        println!("both odd");
    }else{
        println!("different");
    }
三元運算子 ( Ternary Operator ) 
- 也可算是一種 if else 變形。 Rust 支援 let statement 中使用 if
 - 不同分支的回傳結果必須相同。
 
Rust Ternary Operator
//Syntax
let variable = if condition { expression_A } else { expression_B }; //注意最末端有一個分號
let num = 10;
let result = if num%2==0 {"even"} else {"odd"};
- Rust 三元運算其實可以擴大成 block 的寫法。
 
//Syntax
let num = 15;
let result = 
    if num%2==0 {
        if num > 10 {
            "Even and > 10"
        }else{
            "Even and < 10"
        }
    } else {
        if num > 10 {
            "Odd and > 10"
        }else{
            "Odd and < 10"
        }
    };
println!("num is {}", result );
迴圈 ( Loops )
- 迴圈
- for Loop
 - while Loop
 - loop Loop: 無限迴圈,除非遇到 break
 
 - break and continue
- break: Rust 的 break 後方可以搭配 expression,用來拋出回傳值 。
 
 
for Loop
- 當條件發生時中斷迴圈
 
for loop syntax
//for each
for element in list {
    statements...
} 
//for in range
for element in (from..to) {
    statements...
} 
for element in (from..to).rev() {
    statements...
} 
loop Loop
- 無限迴圈,直到遇到 break
 - loop label
 
loop loop syntax
'loop_label: loop{
    statements...
    //break;
    //break expression;
    //break 'loop_label;
}
while Loop
- 當條件發生時中斷迴圈
 
while loop syntax
    while condition {
        statements...
    }
fn main() {
    let mut count_down = 10;
    
    while count_down != 0 {
        println!("{count_down}!");
        count_down -= 1;
    }
    
    println!("Fire!");
}
break continue 中斷迴圈
- Rust 以 break 關鍵字中斷迴圈的語法有三種
- 單純地中斷迴圈
 - 多重迴圈下中斷內層迴圈並繼續指定外層迴圈( 搭配 loop label 使用 )
 - 中斷並拋出回傳值
 
 
Break Syntax
- label :
label name 前方要加一個 ' (單引號),中間不可有空白。
label name 後方要接一個 : (冒號)。 
'loop_label: loop{
    statements...
    //break;
    //break expression;
    //break 'loop_label;
}
Break with lable Example
pub fn break_basic() {
    let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let time = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    'outter: for element in data {
        if element > 7 {
            break;
        }
        'inner: for time in time {
            if time > 5 {
                continue 'outter; //go to label 'outter
                // break 'outter;  //jump to label 'outter and stop
            }
            println!(
                "{} x {} ={} ",
                element.to_string(),
                time.to_string(),
                element * time
            )
        }
        print!("**** end" ); //never print. break while e>7 or t>5.
    }
}
break 中斷並拋出回傳值
首先這個語法讓人想到的第一個疑惑是,
直接 return 回傳值就好了,為何要由 break 來回傳呢?Rust 是 expressive language。
這意味著 Rust 的許多結構甚至是單傳的由大括號包覆的區塊都可以有回傳值。
所以,
第一是 Rust 本身語言的特性使然。
第二,return 是將整個 function 終結, 而 break 僅中斷迴圈。這意味著 function 還活著,還能繼續接下來的 statements。
也就是說,當 loop 並非是 function 的最終行時,用途便出現了。另外,Break with return 似乎只能用在 loop loops。
也就是中斷無限迴圈並給予於一個中斷狀態值。
Block with return
    let result = {
        let a = 10;
        let b = 20;
        a * b // no ending ';', this is the last expr, the retval
        };
    println!("{}" , result.to_string());
Break with return Example
pub fn break_with_return() {
    let mut rng = rand::thread_rng();
    let mut tmp = 0;
    let salt = loop {
        tmp = rng.gen::<i32>();
        if tmp > 100 {
            break tmp; 
            //這邊用 break with return,得到結果並繼續
            //若用 return,則 function 整個中斷。後面列印,gen_key 皆不會執行。
        }
    };
    println!("Found base>100 : {}", salt);
    let key = gen_key(salt);
    println!("sale: {}", key)
}
傳統 OOP 實作比較
pub fn break_with_return2() {
    let salt = rand_num();
    println!("Found base>100 : {}", salt);
    let key = gen_key(salt);
    println!("sale: {}", key)
}
fn rand_num() -> i32 {
    let mut rng = rand::thread_rng();
    let mut tmp = 0;
    let mut salt = 0;
    loop {
        tmp = rng.gen::<i32>();
        if tmp > 100 {
            salt = tmp;
            return salt;
        }
    }
}
## Pattern match: 類似其他語言的 switch/case 分支結構
match example
enum QuestionType {
    DVG(u32),
    Multiple(Vec<u32>),
    FillIn(String),
}
fn fetch_answer(question: QuestionType) -> String {
    match question {
        QuestionType::DVG(dvg) => {
            return extract_dvg_answer(dvg);
        } 
        QuestionType::Multiple(multi) => {
            return extract_multi_answer(multi);
        }, //大括號封裝,所以逗號可省略
        
        QuestionType::FillIn(fillin) => {
            return extract_fillin_answer(fillin);
        }
    }
}
fn extract_dvg_answer(dvganswer: u32) -> String {
    return dvganswer.clone().to_string();
}
fn extract_fillin_answer(fillin: String) -> String {
    return fillin;
}
fn extract_multi_answer(multi: Vec<u32>) -> String {
    let mut combine = "".to_owned();
    for item in multi {
        combine.push_str(&";".to_owned());
        combine.push_str(&item.to_string());
    }
    return combine;
}
pub fn match_exercise() {
    let dvg = QuestionType::DVG(10);
    let multi = QuestionType::Multiple(vec![1, 3, 5]);
    let fillin = QuestionType::FillIn("Hello, I'm Totem.".to_owned());
    println!("-----");
    println!("DVG answer is : {}", fetch_answer(dvg));
    println!("Multiple answer is : {}", fetch_answer(multi));
    println!("FillIn answer is : {}", fetch_answer(fillin));
    
    //DVG answer is : 10
    //Multiple answer is : ;1;3;5
    //FillIn answer is : Hello, I'm Totem.
}
If let condition 
若讓 matching condition 成真則做後續動作。
是 pattern matching 的 syntax sugar。這個語法應該只用在簡化 Patter Matching 情境下。
且意思不同於單純的 if 句子(後面接的是 boolean expression)。
註: 目前應該是因為對 Rust 仍在初學階段,語法原則不明白。所以使用上有非預期的情境出現。
例如:
pattern_condition 中等號兩側 expression 不可互換,
左側必須是 enum 的變體 instance 列舉。
右側應該限定是輸入的條件參數。
pattern_condition : 僅限是 enum 的比對,不同於一般的 if condition。**目前我傾向於少用**,畢竟我對這語法不了解。
if let syntax
- 若(if) 讓/當(let) condition 成真則做後續動作,不然(else) 做另一動作。
 
if let pattern_condition {
    go();
} else {
    wait();
}
if let syntax: 官方範例
// 未使用 sugar 的原始長相:
let onfig_max = Some(3u8);
match onfig_max {
    Some(max)=> println!("最大值為 {}", max),
    _=>(), // do nothing
}
// 等同於
let onfig_max = Some(3u8);
if let  Some(max)= onfig_max {
   println!("最大值為 {}", max);
} else {
    do_nothing();
}
pattern_condition Syntax
- enum_variant : 這邊是 enum 的 static instance。
 - instance : 這邊指的是情境代入的狀態。
 - 這邊似乎左右 expressions 不可互換。
 - 這邊不同於 boolean expression。
 
enum_variant = instance