Синтаксис упаковки и шаблоны `match`

В настоящее время единственный стабильный способ создания Box — это создание с помощью метода Box::new. В стабильной сборке Rust также невозможно деструктурировать Box при использовании сопоставления с шаблоном. В нестабильной сборке может быть использовано ключевое слово box, как для создания, так и для деструктуризации Box. Ниже представлен пример использования:

#![feature(box_syntax, box_patterns)] fn main() { let b = Some(box 5); match b { Some(box n) if n < 0 => { println!("Box contains negative number {}", n); }, Some(box n) if n >= 0 => { println!("Box contains non-negative number {}", n); }, None => { println!("No box"); }, _ => unreachable!() } }
#![feature(box_syntax, box_patterns)]

fn main() {
    let b = Some(box 5);
    match b {
        Some(box n) if n < 0 => {
            println!("Box contains negative number {}", n);
        },
        Some(box n) if n >= 0 => {
            println!("Box contains non-negative number {}", n);
        },
        None => {
            println!("No box");
        },
        _ => unreachable!()
    }
}

Обратите внимание, что эти возможности в настоящее время являются скрытыми: box_syntax (создание упаковки) и box_patterns (деструктурирование и сопоставление с образцом), потому что синтаксис все еще может измениться в будущем.

Возврат указателей

Во многих языках с указателями, вы можете вернуть указатель из функции, чтобы таким образом избежать копирования большой структуры данных. Например:

struct BigStruct { one: i32, two: i32, // etc one_hundred: i32, } fn foo(x: Box<BigStruct>) -> Box<BigStruct> { Box::new(*x) } fn main() { let x = Box::new(BigStruct { one: 1, two: 2, one_hundred: 100, }); let y = foo(x); }
struct BigStruct {
    one: i32,
    two: i32,
    // etc
    one_hundred: i32,
}

fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
    Box::new(*x)
}

fn main() {
    let x = Box::new(BigStruct {
        one: 1,
        two: 2,
        one_hundred: 100,
    });

    let y = foo(x);
}

Идея состоит в том, что, при передаче упаковки, происходит копирование только указателя, а не всех int, из которых состоит BigStruct.

Это антипаттерн в Rust. Вместо этого следует написать так:

#![feature(box_syntax)] struct BigStruct { one: i32, two: i32, // etc one_hundred: i32, } fn foo(x: Box<BigStruct>) -> BigStruct { *x } fn main() { let x = Box::new(BigStruct { one: 1, two: 2, one_hundred: 100, }); let y: Box<BigStruct> = box foo(x); }
#![feature(box_syntax)]

struct BigStruct {
    one: i32,
    two: i32,
    // etc
    one_hundred: i32,
}

fn foo(x: Box<BigStruct>) -> BigStruct {
    *x
}

fn main() {
    let x = Box::new(BigStruct {
        one: 1,
        two: 2,
        one_hundred: 100,
    });

    let y: Box<BigStruct> = box foo(x);
}

Это дает вам гибкость без ущерба для производительности.

Вы можете подумать, что такое использование даст нам ужасную производительность: возвращается значение, а затем оно сразу упаковывается?! Разве это не паттерн худшего из двух миров? Rust намного умнее. В этом коде не происходит копирование. main выделяет достаточно места для box, передает указатель на эту память в foo в виде x, а затем foo записывает значение прямо в Box<T>.

Это достаточно важно, поэтому стоит повторить: указатели не для оптимизации возвращаемых значений в коде. Позвольте вызывающей стороне самой выбрать, как она хочет использовать выход.