rust 流程控制

1、if

1. if-else if -else

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);
  }
}

2. 表达式语句

fn main()
{
  let x = 5;
  let y = if x == 5 { 10 } else { 15 };
  let z = if x == 5 { 10 } else if x == 6 { 15 } else if x == 7 { 20 } else { 25 };
}

2、for

1. for(x = 0; x < 10; x++);

fn main() {
  for x in 0..10 {
    println!("{}", x); // x: i32
  }
}
➜  main make
rustc main.rs
./main
0
1
2
3
4
5
6
7
8
9
➜  main

2. for-in 迭代

fn main()
{
  for var in [10; 5].iter() {
    print!("{:?} ", var)
  }
  println!("");
}

3、loop

1. loop 死循环

fn main() {
  let mut n = 1;
  loop {
    n += 1;
    if n == 5 {break};
  }
}

2. loop嵌套

fn main()
{
  // 外层喜欢循环,使用outer标记符
  'outer: loop {
  println!("Entered the outer loop");

    // 内层喜欢循环,使用inner标记符
   'inner: loop { 
      println!("Entered the inner loop");
      break 'outer; // 结束外层循环
    }
    println!("This point will never be reached");
  }

  println!("Exited the outer loop");
}
➜  main make
rustc main.rs
warning: unreachable statement
  --> main.rs:12:5
   |
12 |     println!("This point will never be reached");
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: #[warn(unreachable_code)] on by default
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

./main
Entered the outer loop
Entered the inner loop
Exited the outer loop
➜  main

4、while(条件) {}

fn main() {
  let mut n = 1;

  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);
    }
    n += 1;
  }
}

5、match

1. 类似switch-case语法结构

fn main() {
  let day = 5;

  match day {
    0 | 6 => println!("weekend"), // case 0和6具体值
    1 ... 5 => println!("weekday"), // case [1,5] 范围
    _ => println!("invalid"), // default 
  }
}
➜  main make
rustc main.rs
./main
weekday
➜  main

2. 使用@绑定进入case项的值

fn main() {
  let x = 1;
  
  match x {
    e @ 1 ... 5 => println!("got a range element {}", e),
    _ => println!("anything"),
  }
}

3. 使用ref绑定进入case项值的引用

fn main() {
  let x = 5;
  let mut y = 5;

  match x {
    // the `r` inside the match has the type `&i32`
    ref r => println!("Got a reference to {}", r),
  }

  match y {
    // the `mr` inside the match has the type `&i32` and is mutable
    ref mut mr => println!("Got a mutable reference to {}", mr),
  }
}

4. case 元祖

fn main() {
  let pair = (0, -2);

  match pair {
    (0, y) => println!("x is `0` and `y` is `{:?}`", y),
    (x, 0) => println!("`x` is `{:?}` and y is `0`", x),
    _ => println!("It doesn't matter what they are"),
  }
}
➜  main make
rustc main.rs
./main
x is `0` and `y` is `-2`
➜  main

5. case struct

struct Point {
  x: i32,
  y: i32,
}

fn main() {
  let origin = Point { x: 1, y: 2 };

  // 获取Point实例成员x的值
  match origin {
    Point { x:1, .. } => println!("x == 1"),
    // Point { .. , y:2 } => println!("y == 2"), 不能比较后面的值
    _ => println!("It doesn't matter what they are"),
  }
}
➜  main make
rustc main.rs
warning: field is never used: `y`
 --> main.rs:3:3
  |
3 |   y: i32,
  |   ^^^^^^
  |
  = note: #[warn(dead_code)] on by default

./main
x == 1
➜  main

6. case enum

enum OptionalInt {
  Value(i32),
  Missing,
}

fn main()
{
  let x = OptionalInt::Value(5);

  match x {
    OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
    OptionalInt::Value(..) => println!("Got an int!"),
    OptionalInt::Missing => println!("No such luck."),
    _ => println!("It doesn't matter what they are"),
  };
}
➜  main make
rustc main.rs
./main
Got an int!
➜  main

6、if let 可选值解包

fn main()
{
  // Some()可选值
  let number = Some(7);

  // if let 解包
  if let Some(i) = number {
    println!("Matched {:?}!", i);
  } else {
    println!("Didn't match a number!");
  }
}
➜  main make
rustc main.rs
./main
Matched 7!
➜  main

7、while let

fn main()
{
  // 可选值
  let mut optional = Some(0);

  // Some(0) => Some(i) ==> i == 0
  while let Some(i) = optional {
    if i > 9 {
      println!("Greater than 9, quit!");
      optional = None; // 可选值赋值为None
    } else {
      println!("`i` is `{:?}`. Try again.", i);
      optional = Some(i + 1); // 可选值+1后,继续打包为可选值
    }
  }
}
➜  main make
rustc main.rs
./main
`i` is `0`. Try again.
`i` is `1`. Try again.
`i` is `2`. Try again.
`i` is `3`. Try again.
`i` is `4`. Try again.
`i` is `5`. Try again.
`i` is `6`. Try again.
`i` is `7`. Try again.
`i` is `8`. Try again.
`i` is `9`. Try again.
Greater than 9, quit!
➜  main

8、函数

1. 全局函数

#[allow(dead_code)] // 禁用无效代码检查
fn add_one(x: i32) -> i32 {
  x + 1
}

fn main()
{
  println!("{}", add_one(9));
}
➜  main make
rustc main.rs
./main
10
➜  main

2. 函数抛异常

fn diverges() -> ! {
  panic!("This function never returns!");
}

fn main()
{
  diverges();
}
➜  main make
rustc main.rs
./main
thread 'main' panicked at 'This function never returns!', main.rs:2:3
note: Run with `RUST_BACKTRACE=1` for a backtrace.
make: *** [all] Error 101
➜  main

其中panic!是一个宏,使当前执行线程崩溃并打印给定信息。

3. 匿名函数

1. 简单使用

fn main()
{
  let num = 5;
  let plus_num = |x: i32| x + num; // 默认 return (x + num);
  println!("{}", plus_num(10));
}
➜  main make
rustc main.rs
./main
15
➜  main

2. move让闭包获取外部变量的所有权

fn main()
{
  let mut num = 5;
  println!("{}", num);

  {
    let mut add_num = move |x: i32| {num += x; num};   // 闭包通过move获取了num的所有权
    println!("{}", add_num(7));
    println!("{}", num);
  }

  println!("{}", num);
}
➜  main make
rustc main.rs
./main
5
12
5
5
➜  main

4. 高阶函数

1. 直接调用函数

fn add_one(x: i32) -> i32 {
  x + 1
}

fn main() {
  // 直接调用函数
  let f0 = add_one(2i32) * 2;
  println!("{}", f0);
}
➜  main make
rustc main.rs
./main
6
➜  main

2. 函数作为参数传递

fn add_one(x: i32) -> i32 {
  x + 1
}

// where 控制模板参数F的类型是【Fn(i32) -> i32】
fn apply(f: F, y: i32) -> i32 where F: Fn(i32) -> i32
{
  f(y) * y
}

fn main() {
  // 将add_one函数作为参数传递给apply()
  let f1 = apply(add_one, 2);
  println!("{}", f1);

  // 将add_one赋值给函数指针变量,再传递给apply()
  let transform: fn(i32) -> i32 = add_one;
  let f2 = apply(transform, 2);
  println!("{}", f2);
}
➜  main make
rustc main.rs
./main
6
6
➜  main

3. 闭包作为函数参数

// where 控制模板参数F的类型是【Fn(i32) -> i32】
fn apply(f: F, y: i32) -> i32 where F: Fn(i32) -> i32
{
  f(y) * y
}

fn main() {
  // 定义闭包,再传递闭包给函数
  let closure = |x: i32| x + 1;
  let f1 = apply(closure, 2);

  // 直接传递闭包
  let f2 = apply(|x| x + 1, 2);
  println!("{}, {}", f1, f2);
}
➜  main make
rustc main.rs
./main
6, 6
➜  main

4. 返回Box打包的闭包

// 返回值为【Fn 函数名(x: i32) -> i32】函数类型的指针
fn factory(x: i32) -> Box i32> {
  Box::new(move |y| x + y)
}

fn main() {
  let box_fn = factory(1i32);
  let b0 = box_fn(2i32) * 2;
  let b1 = (*box_fn)(2i32) * 2;
  let b2 = (&box_fn)(2i32) * 2;
  println!("{}, {}, {}", b0, b1, b2);
}
➜  main make
rustc main.rs
./main
6, 6, 6
➜  main

9、宏定义

1. 定义宏指令与调用宏指令

eg1

// 宏指令定义
macro_rules! foo {
  // 左侧匹配任意的字符串 => {{要执行的语句}};
  ( $( $x:expr ), * ) => {{println!("hello")}};
}

fn main() {
  foo!(); // 宏指令调用,区别于函数调用,使用!符号
  foo!(1);
  foo!(1,2);
  foo!(hello);
}
➜  main make
rustc main.rs
./main
hello
hello
hello
hello
➜  main

eg2

macro_rules! foo {
  () => (fn x() { println!("hello") });
}

fn main() {
  foo!(); // 替换为 (fn x() { println!("hello") });
  x(); 
}
➜  main make
rustc main.rs
./main
hello
➜  main

eg3

macro_rules! foo {
  ($v:ident) => (let $v = 10);
}

fn main() {
  foo!(x); // 
  println!("{}", x);
}
➜  main make
rustc main.rs
warning: expected `;`, found ``
 --> main.rs:3:27
  |
3 |   ($v:ident) => (let $v = 10);
  |                           ^^
...
7 |   foo!(x); //
  |   -------- in this macro invocation
  |
  = note: This was erroneously allowed and will become a hard error in a future release

./main
10
➜  main

运行虽然正常,但是会报警告,不建议通过宏定义替换为变量定义。

3. 常规宏指令的模式匹配

macro_rules! my_print {
  // ( $( $x:expr ),* )
  // => $( $x:expr ) 重复匹配多次
  // => $x:expr 将expr匹配值绑定给变量x
  // => 后面使用 $x 获取匹配值
  ( $( $x:expr ),* ) => {{
    $(print!("{0}, ",$x);)*;  // 让 $(temp_vec.push($x);) 重复匹配多次
    println!("")
  }};
}

fn main()
{
  my_print!(1,2,3);
  my_print!(1,2,3,4,5,6);
  my_print!(1,2,3, "hello", "world", "worinima");
}
➜  main make
rustc main.rs
./main
1, 2, 3,
1, 2, 3, 4, 5, 6,
1, 2, 3, hello, world, worinima,
➜  main

2. 自定义宏指令的模式匹配

macro_rules! foo {
  (x => $e:expr) => (println!("mode X: {}", $e));
  (y => $e:expr) => (println!("mode Y: {}", $e));
}

/**
macro_rules! foo {
  匹配规则 => {{ ...匹配中之后执行的语句... }};
  (x => $e:expr) => {{println!("mode X: {}", $e)}};
  (y => $e:expr) => {{println!("mode Y: {}", $e)}};
}
*/

fn main() {
  foo!(x => 3);
  foo!(y => 4);
  foo!(y => 5);
  // foo!(z => 6); // error
}
➜  main make
rustc main.rs
./main
mode X: 3
mode Y: 4
mode Y: 5
➜  main

4. 示例1

// 宏定义
macro_rules! my_vec {
  ( $( $x:expr ),* ) => {{
    let mut temp_vec = Vec::new();
    $(temp_vec.push($x);)*;  // 让 $(temp_vec.push($x);) 重复匹配多次
    temp_vec
  }};
}

fn main()
{
  // 通过语句创建Vec对象
  {
    let x: Vec = {
      let mut temp_vec = Vec::new();
      temp_vec.push(1);
      temp_vec.push(2);
      temp_vec.push(3);
      temp_vec
    };
    println!("x = {:?}", x);
  }
    
  // 宏定义替换如上创建Vec的所有代码
  {
    let y = my_vec!(1,2,3); // => $(temp_vec.push($x);)* 匹配
    println!("y = {:?}", y);
  }
}


➜  main make
rustc main.rs
./main
x = [1, 2, 3]
y = [1, 2, 3]
➜  main

5. 示例2:递归解析HTML

macro_rules! write_html {
  // 匹配1(递归结束分支)
  ($w:expr, ) => (());

  // 匹配2
  ($w:expr, $e:tt) => {{
    println!("2 => $w = {}, $e = {}", $w, $e);
    write!($w, "{}", $e)
  }};

  // 匹配3
  ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)* ) => {{
    println!("3.1 => $w = {}, stringify!($tag) = {}", $w, stringify!($tag));
    write!($w, "<{}>", stringify!($tag));
    write_html!($w, $($inner)*);
    println!("3.2 => $w = {}, stringify!($tag) = {}", $w, stringify!($tag));
    write!($w, "", stringify!($tag));
    write_html!($w, $($rest)*);
  }};
}

fn main() {
  use std::fmt::Write;
  let mut out = String::new();

  write_html!(
    &mut out,
    html[head[title["Main Title"]]body[h1["H1 Sub Title"]]]
  );

  println!("out = {:?}", out);
}
➜  main make
rustc main.rs
3.1 => $w = , stringify!($tag) = html
3.1 => $w = , stringify!($tag) = head
3.1 => $w = , stringify!($tag) = title
2 => $w = , $e = Main Title
3.2 => $w = <html><head><title>Main Title, stringify!($tag) = title
3.2 => $w = <html><head><title>Main Title, stringify!($tag) = head
3.1 => $w = Main Title, stringify!($tag) = body
3.1 => $w = Main Title, stringify!($tag) = h1
2 => $w = Main Title

, $e = H1 Sub Title 3.2 => $w = Main Title

H1 Sub Title, stringify!($tag) = h1 3.2 => $w = Main Title

H1 Sub Title

, stringify!($tag) = body 3.2 => $w = Main Title

H1 Sub Title

, stringify!($tag) = html out = "Main Title

H1 Sub Title

" ➜ main

在一个匹配器中,每个元变量都有一个“片段说明符”,来识别匹配哪些语法形式。

  • ident:标识符。例如:x; foo
  • path:一个合格的名字。例如: T::SpecialA
  • expr: 一个表达式。例如:2 + 2; if true then { 1 } else { 2 }; f(42)
  • ty:一个类型。例如:i32; Vec<(char, String)>; &T
  • pat:一个模式。例如: Some(t); (17, 'a'); _
  • stmt:单个语句。例如: let x = 3
  • block:一个括号分隔的语句序列。例如: { log(error, "hi"); return 12; }
  • item:一个项目。例如: fn foo() { }; struct Bar;
  • meta:一个 "元项目", 在属性中建立的。 例如: cfg(target_os = "windows")
  • tt:一个单个标记树。

6. 常见的宏

1. panic!

panic!("oh no!");

2. vec!

let v = vec![1, 2, 3, 4, 5];
let v = vec![0; 100];

3. assert! 和 assert_eq!

// A-ok!

assert!(true);
assert_eq!(5, 3 + 2);

// nope :(

assert!(5 < 3);
assert_eq!(5, 3);

4. try!

use std::fs::File;

fn foo() -> std::io::Result<()> {
  let f = try!(File::create("foo.txt"));
  Ok(())
}

你可能感兴趣的:(rust 流程控制)