• 装箱语法和模式
    • 返回指针

    装箱语法和模式

    box-syntax-and-patterns.md


    commit 28548db57d0acbc00ee80b43816953dbe31d53ba

    目前唯一稳定的创建Box的方法是通过Box::new方法。并且不可能在一个模式匹配中稳定的析构一个Box。不稳定的box关键字可以用来创建和析构Box。下面是一个用例:

    1. #![feature(box_syntax, box_patterns)]
    2. fn main() {
    3. let b = Some(box 5);
    4. match b {
    5. Some(box n) if n < 0 => {
    6. println!("Box contains negative number {}", n);
    7. },
    8. Some(box n) if n >= 0 => {
    9. println!("Box contains non-negative number {}", n);
    10. },
    11. None => {
    12. println!("No box");
    13. },
    14. _ => unreachable!()
    15. }
    16. }

    注意这些功能目前隐藏在box_syntax(装箱创建)和box_patterns(析构和模式匹配)gate 之后因为它的语法在未来可能会改变。

    返回指针

    在很多有指针的语言中,你的函数可以返回一个指针来避免拷贝大的数据结构。例如:

    1. struct BigStruct {
    2. one: i32,
    3. two: i32,
    4. // Etc.
    5. one_hundred: i32,
    6. }
    7. fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
    8. Box::new(*x)
    9. }
    10. fn main() {
    11. let x = Box::new(BigStruct {
    12. one: 1,
    13. two: 2,
    14. one_hundred: 100,
    15. });
    16. let y = foo(x);
    17. }

    要点是通过传递一个装箱,你只需拷贝了一个指针,而不是那构成了BigStruct的一百个int值。

    上面是 Rust 中的一个反模式。相反,这样写:

    1. #![feature(box_syntax)]
    2. struct BigStruct {
    3. one: i32,
    4. two: i32,
    5. // Etc.
    6. one_hundred: i32,
    7. }
    8. fn foo(x: Box<BigStruct>) -> BigStruct {
    9. *x
    10. }
    11. fn main() {
    12. let x = Box::new(BigStruct {
    13. one: 1,
    14. two: 2,
    15. one_hundred: 100,
    16. });
    17. let y: Box<BigStruct> = box foo(x);
    18. }

    这在不牺牲性能的前提下获得了灵活性。

    你可能会认为这会给我们带来很差的性能:返回一个值然后马上把它装箱?难道这在哪里不都是最糟的吗?Rust 显得更聪明。这里并没有拷贝。main为装箱分配了足够的空间,向foo传递一个指向他内存的x,然后foo直接向Box<T>中写入数据。

    因为这很重要所以要说两遍:返回指针会阻止编译器优化你的代码。允许调用函数选择它们需要如何使用你的输出。