macro_rules!

在Rust中,宏非常之强大,宏就像一个函数一样,但是接着!However, unlike macros in C and other languages, Rust macros are expanded into abstract syntax trees, rather than string preprocessing, so you don’t get unexpected precedence bugs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 将() 展开为打印字符
macro_rules! say_hello{
    () => {
        println!("Hello!");
    };
}

fn main() {
    say_hello!()
}

Designators

通过一种宏来创建函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
macro_rules! create_function{
    ($func_name:ident)  => {
        fn $func_name() {
            println!("You called {:?}()",
                     stringify!($func_name));
        }
    };
}
create_function!(foo);

fn main()
{
    foo()
}

Repeat

可以使用宏来进行递归

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use core::cmp::min;
macro_rules! find_min {
    ($x:expr) => ($x);
    ($x:expr,  $($y:expr), +) =>{
        min($x, find_min!($($y),+))
    }
}
fn main()
{
    println!("{}", find_min!(1u32));
    println!("{}", find_min!(0u32, 3u32));
    println!("{}", find_min!(1u32, 5u32, 5u32));
}

Error handling

Rust安全性部分归因于对错误的正确处理。

An explicit panic is mainly useful for tests and dealing with unrecoverable errors. For prototyping it can be useful, for example when dealing with functions that haven’t been implemented yet, but in those cases the more descriptive unimplemented is better. In tests panic is a reasonable way to explicitly fail.

The Option type is for when a value is optional or when the lack of a value is not an error condition. For example the parent of a directory - / and C: don’t have one. When dealing with Options, unwrap is fine for prototyping and cases where it’s absolutely certain that there is guaranteed to be a value. However expect is more useful since it lets you specify an error message in case something goes wrong anyway.

When there is a chance that things do go wrong and the caller has to deal with the problem, use Result. You can unwrap and expect them as well (please don’t do that unless it’s a test or quick prototype).

panic!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fn give_princess(gift: &str) {
    // Princesses hate snakes, so we need to stop if she disapproves!
    if gift == "snake" { panic!("AAAaaaaa!!!!"); }

    println!("I love {}s!!!!!", gift);
}

fn main() {
    give_princess("teddy bear");
    give_princess("snake");
}

Option & unwrap

更多时候Rust采用Option来增强程序的可读性。

1
2
3
4
5
6
7
8
fn give_princess(gift: Option<&str>) {
    let inside = gift.unwrap();
    println!("I love {}s!!!!!", inside);
}
fn main() {
    let bird = Some("robin");
    give_princess(bird);
}

在这里,可以使用match机制来将Option中的内容获取,但是更简单的方法是使用?。有个地方需要注意如果该机制放在函数中,返回值不能是空!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn give_princess(gift: Option<&str>) -> Option<String> {
    let inside:&str = gift?;
    Some(format!("{}", inside))

}
fn main() {
    let bird = Some("robin");
    let y = give_princess(bird);
    println!("{}", y.unwrap());
}

Result

Result是比Option更加先进的一种错误处理机制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let s = "10";
    let num = match s.parse::<i32>() {
        Ok(x) => x,
        Err(e) => return Err(e),
    };

    Ok(())
}


use std::num::ParseIntError;

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    let first_number = first_number_str.parse::<i32>()?;
    let second_number = second_number_str.parse::<i32>()?;

    Ok(first_number * second_number)
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    print(multiply("10", "2"));
    print(multiply("t", "2"));
}

参考