В настоящее время единственный стабильный способ создания 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!() } }
Обратите внимание, что эти возможности в настоящее время являются скрытыми:
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>
.
Это достаточно важно, поэтому стоит повторить: указатели не для оптимизации возвращаемых значений в коде. Позвольте вызывающей стороне самой выбрать, как она хочет использовать выход.