% Синтаксис упаковки и шаблоны 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!()
}
}
Обратите внимание, что эти возможности в настоящее время являются скрытыми:
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);
}
Идея состоит в том, что, при передаче упаковки, происходит копирование только
указателя, а не всех 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);
}
Это дает вам гибкость без ущерба для производительности.
Вы можете подумать, что такое использование даст нам ужасную производительность:
возвращается значение, а затем оно сразу упаковывается?! Разве это не паттерн
худшего из двух миров? Rust намного умнее. В этом коде не происходит
копирование. main
выделяет достаточно места для box
, передает указатель на
эту память в foo
в виде x
, а затем foo
записывает значение прямо в
Box<T>
.
Это достаточно важно, поэтому стоит повторить: указатели не для оптимизации возвращаемых значений в коде. Позвольте вызывающей стороне самой выбрать, как она хочет использовать выход.