Post

rust 编码模式

rust 编码模式

设计模式

  • Design Patterns: 是在编写软件时解决常见问题的方法。
  • Anti-patterns: 反模式是解决这些相同常见问题的方法。 然而,虽然设计模式给我们带来了好处,但反模式却带来了更多的问题。
  • idioms(惯用方法): 是编码时要遵循的准则。 它们是社区的社会规范。 你可以打破它们,但如果你这样做了,你应该有一个很好的理由。

    示例:

  • 使用 borrowed type 作为 参数(为参数提供灵活), 例如: &str 替换 &String, &[T] 替换 &Vec[T]
  • 使用format! 拼接字符串: 该方法是最清晰、可读的 组合string的方法, 缺点是 并不是最高效的。
  • 提供 static new 方法 作为 构造方法
  • Default trait 实现: 提供默认的构造方法, new 则提供具体参数的构造方法
  • Collection 是 smart pointers: 一般的collect 实现了 Deref trait 来 提供 smart pointers
    • 优势: 提供更多的灵活性
    • 劣势: 边界检查时不考虑仅通过解引用可用的方法和特征,因此使用这种模式的数据结构的泛型编程可能会变得复杂(参见 Borrow 和 AsRef 特征等)。
  • rust 没有提供 finally 代码块: 函数可能存在多个返回点, 导致 finally块(退出时执行)变得困难,对于 ? macro, panick 来说更是如此, 所以rust 并没有提供 finally 块, 相反的 对象的 Drop trait中的drop方法 总是调用,无论怎样退出。(但是在drop 中发生panic 会导致 线程终止,从而不能够运行所有的 析构drop函数, 所以 drop 析构函数 可能并不能够得到保障,所以 需要在drop中格外小心,不能panic)
  • mem::take, mem::replace 来 替换已有的enum中的数值, 示例: 我们使用 mem::take 来 将数值 使用 default 替换 并返回前值。 replace 则需要自己提供 数值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    use std::mem;
    
    enum MyEnum {
        A { name: String, x: u8 },
        B { name: String }
    }
    
    fn a_to_b(e: &mut MyEnum) {
        if let MyEnum::A { name, x: 0 } = e {
            // this takes out our `name` and put in an empty String instead
            // (note that empty strings don't allocate).
            // Then, construct the new enum variant (which will
            // be assigned to `*e`).
            *e = MyEnum::B { name: mem::take(name) }
        }
    }
    
  • 在 stack 上 进行动态分发(dynamic dispatch): rust 只保证 每个使用到的 变量 是 初始化过的。所以 可以存在未使用的变量 是未初始化的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use std::io;
use std::fs;


// These must live longer than `readable`, and thus are declared first:
let (mut stdin_read, mut file_read);

// We need to ascribe the type to get dynamic dispatch.
let readable: &mut dyn io::Read = if arg == "-" {
    stdin_read = io::stdin();
    &mut stdin_read
} else {
    file_read = fs::File::open(arg)?;
    &mut file_read
};

// Read from `readable` here.

  • Option 可以被 视为 Interator, 一个 包装 None 或者 element 的iterator, 可以如下使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let turing = Some("Turing");
let mut logicians = vec!["Curry", "Kleene", "Markov"];

logicians.extend(turing);

// equivalent to
if let Some(turing_inner) = turing {
    logicians.push(turing_inner);
}



let turing = Some("Turing");
let logicians = vec!["Curry", "Kleene", "Markov"];

for logician in logicians.iter().chain(turing.iter()) {
    println!("{} is a logician", logician);
}
  • private in struct: struct 中private field 可以 使用如下模式 来进行修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mod a {
    // Public struct.
    pub struct S {
        pub foo: i32,
        // Private field.
        bar: i32,
    }
}

fn main(s: a::S) {
    // Because S::bar is private, it cannot be named here and we must use `..`
    // in the pattern.
    let a::S { foo: _, ..} = s;
}

  • temporary mutable 暂时性的 mut:
1
2
3
4
5
6
7
8
9
10
11
// 使用 内嵌的 {} 嵌套代码
let data = {
    let mut data = get_vec();
    data.sort();
    data
};

// 重新绑定
let mut data = get_vec();
data.sort();
let data = data;
This post is licensed under CC BY 4.0 by the author.