注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
今のところ、安定版において 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の作成)、 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); }
考え方としては、boxで渡すことで BigStruct
を構成する100個の i32
の代わりにポインタのみのコピーで済む、というものです。
これは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); }
このように書くことでパフォーマンスを犠牲にすることなく、柔軟性を確保することができます。
このコードはひどいパフォーマンス低下をもたらすと感じるかもしれません。値を返して即座にboxに入れるなんて?! このパターンは悪いところどりになっているのでは? Rustはもう少し賢いため、このコードでコピーは発生しません。 main
内では box
のために十分なメモリ領域を確保し、そのメモリへのポインタを foo
へ x
として渡します。 foo
はその値を直接 Box<T>
(訳注: すなわち y
)の中に書き込みます。
重要なことなので繰り返しますが、ポインタを戻り値の最適化のために使うべきではありません。呼び出し側が戻り値をどのように使うかを選択できるようにしましょう。