From b7c4735aa31b27ba29d30528a6d946325b0eed2c Mon Sep 17 00:00:00 2001 From: tnk Date: Mon, 9 Feb 2026 16:32:55 +0900 Subject: [PATCH 01/14] add boxed module --- src/SUMMARY.md | 1 + src/boxed/about.md | 133 +++++++++++++++++++++++++++++++++++++++++++++ src/modlist.md | 1 + 3 files changed, 135 insertions(+) create mode 100644 src/boxed/about.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 84c48e6..99555cf 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -7,6 +7,7 @@ # リファレンス - [std::any](./any/about.md) +- [std::boxed](./boxed/about.md) - [std::vec](./vec/about.md) - [Drain](./vec/Drain.md) diff --git a/src/boxed/about.md b/src/boxed/about.md new file mode 100644 index 0000000..abce9e2 --- /dev/null +++ b/src/boxed/about.md @@ -0,0 +1,133 @@ +# モジュール `std::boxed` + +## バージョン + +Rust 1.0.0 ~ + +## 概要 + +`Box`はヒープアロケーションに分類される。 + +[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)(単に ‘Box’ と呼ばれることもある)はRustにおいて一番単純なヒープアロケーションである。Boxはこのアロケーションの所有権を有し、スコープから外れる時に中身を破棄する。加えて、ヒープの割り当てが`isize::MAX`バイトを超えないことも保証する。 + +## 例 + +[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)を作成してスタックの値をヒープへ移動する: + +```rust +let val: u8 = 5; +let boxed: Box = Box::new(val); +``` + +[参照外し](https://doc.rust-lang.org/std/ops/trait.Deref.html)によって[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)からスタックへ値を移動する: + +```rust +let boxed: Box = Box::new(5); +let val: u8 = *boxed; +``` + +再帰構造の作成: + +```rust +#[derive(Debug)] +enum List { + Cons(T, Box>), + Nil, +} + +let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil)))); +println!("{list:?}"); +``` + +上記のプログラムの結果は`Cons(1, Cons(2, Nil))`となる。 +再帰構造にはBox化が必要である。例えば`Cons`を下記のように定義した場合コンパイルエラーとなる: + +```rust +Cons(T, List), +``` + +なぜなら`List`のスタックサイズはリスト内にどれだけのリストがあるかにより、このままでは`Cons`に対するスタックの割り当て量を把握できないためである。スタックサイズが決まっている[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)の導入により、`Cons`に必要なスタックサイズが把握できるようになる。 + +## メモリーレイアウト + +サイズが0でない値では、[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)はメモリー割り当てのため[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターを使用する。アロケーターとともに使用される[`Layout`](https://doc.rust-lang.org/std/alloc/struct.Layout.html)が適切な型であり、生ポインターがその型の有効な値を示す場合に、[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)と[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターに割り当てられた生ポインターは相互に変換できる。より詳しく言うと、[`Layout::for_value(&*value)`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value)とともに使用される[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターに割り当てられた`value: *mut T`は[`Box::::from_raw(value)`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.from_raw)を使用してBoxへと変換できる。逆に[`Box::::into_raw`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw)から得られた`value: *mut T`は[`Layout::for_value(&*value)`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value)と[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターによって解放できる。 + +サイズが0の値では、`Box`は非ヌルでありアライメントされている必要がある。`Box::new`が使用できない場合にZST(ゼロサイズ型)のBoxを作成する推奨方法は[`ptr::NonNull::dangling`](https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling)を使用することである。 + +これらの基本的なLayoutの要件に加えて、`Box`は有効な値`T`を示さなければならない。 + +`T: Sized`である限り`Box`は単一のポインターであることを保証するとともにCのポインター(CのT*型)とのABI互換性を持つ。これはRustでCから呼び出す関数を作成する際に`Box`で定義したものがCでは`T*`になるという意味である。例として`Foo`の作成と破棄を行う関数を宣言するCのヘッダーをあげる: + +```C +/* C header */ + +/* Returns ownership to the caller */ +struct Foo* foo_new(void); + +/* Takes ownership from the caller; no-op when invoked with null */ +void foo_delete(struct Foo*); +``` + +この2つの関数はRustで下記のように実装できる。ここでは`struct Foo*`型に変換された`Box`は所有権の制約を補足する。`Box`が非ヌルであるため引数がヌルになる可能性のある`foo_delete`の引数はRustでは`Option>`になることに注意しなければならない。 + +```rust +#[repr(C)] +pub struct Foo; + +#[unsafe(no_mangle)] +pub extern "C" fn foo_new() -> Box { + Box::new(Foo) +} + +#[unsafe(no_mangle)] +pub extern "C" fn foo_delete(_: Option>) {} +``` + +`Box`はCのABIにおいてCのポインターと同じ表現を持つが、これはいつでも`T*`を`Box`へ変換したり変換したものが上手く機能するという意味ではない。`Box`の値は常にメモリーアライメントされた非ヌルのポインターであり、デストラクターはグローバルアロケーターでの値の開放を試みる。一般的なベストプラクティスは`Box`をグローバルアロケーターから生成されるポインターとしてのみ使用することである。 + +**重要** 少なくとも現時点ではRustから呼び出されるCで定義された関数の型に`Box`を使用すべきではない。この場合ではCの型に可能な限り近い型を直接使用すべきである。[`rust-lang/unsafe-code-guidelines#198`](https://github.com/rust-lang/unsafe-code-guidelines/issues/198)に記載されているように、`Box`をCの定義で単に`T*`のように使用すると未定義動作につながることがある。 + +## アンセーフなコードへに対する考慮 + +**注意:このセクションは規範的でなく変更の可能性を含んでおり、将来的に緩和される可能性がある。これは現在コンパイラーに実装されていルールの要約である。** + +`Box`へのエイリアスのルールは`&mut T`と同じものである。`Box`は保有する中身の一意性を持つ。`&mut T`のような移動や借用によって変更されたBoxから取得した生ポインターの使用は許可されていない。[`rust-lang/unsafe-code-guidelines#326`](https://github.com/rust-lang/unsafe-code-guidelines/issues/326)にアンセーフなコードでのBoxの使用に関する更なる説明がある。 + +## エディション + +[このドキュメント](https://doc.rust-lang.org/std/primitive.array.html)にある通り、Rust 2021までのエディションの配列には`IntoIterator`の実装の特別なケースが存在する。後にBox化したスライスにも同様の回避策を追加する必要が判明したため、残念ながら回避策の適用は2024エディションになった。 + +具体的には、`IntoIterator`はすべてのエディションの`Box<[T]>`に実装されているが、Box化したスライスに対する`into_iter()`の適用は2024以前のエディションの実装に従う。 + +```rust +// Rust 2015, 2018, 2021: + +let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice(); + +// スライスから各々の値を参照した iterator を作成する。 +for item in boxed_slice.into_iter().enumerate() { + let (i, x): (usize, &i32) = item; + println!("boxed_slice[{i}] = {x}"); +} + +//`boxed_slice_into_iter`は将来の互換性のため、リンターに下記への変更を提案される: +for item in boxed_slice.iter().enumerate() { + let (i, x): (usize, &i32) = item; + println!("boxed_slice[{i}] = {x}"); +} + +// Box 化したスライスから値の iterator を作成する場合、`IntoIterator::into_iter`を使用して明示的に宣言できる。 +for item in IntoIterator::into_iter(boxed_slice).enumerate() { + let (i, x): (usize, i32) = item; + println!("boxed_slice[{i}] = {x}"); +} +``` + +配列の実装と同様に、このオーバーライドは将来修正される可能性があり、後方互換性を維持したい場合はこれらのエディション間の違いに頼った挙動を避けるべきである。 + +## 構造体 + +| 名前 | 説明 | +| --------------------------------------------------------------------------------- | ---------------------------------------- | +| [Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) | T 型のヒープを一意に所有するポインター型 | +| [ThinBox](https://doc.rust-lang.org/std/boxed/struct.ThinBox.html) (Experimental) | 薄い Box | \ No newline at end of file diff --git a/src/modlist.md b/src/modlist.md index d970331..58081a6 100644 --- a/src/modlist.md +++ b/src/modlist.md @@ -3,4 +3,5 @@ 現在掲載されているモジュールの一覧です。 - [std::any](./any/about.md) +- [std::boxed](./boxed/about.md) - [std::vec](./vec/about.md) From 79536f6d6dd1fd8d01c00800db7a048885066dfa Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:20:45 +0900 Subject: [PATCH 02/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index abce9e2..40777e9 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -26,7 +26,7 @@ let boxed: Box = Box::new(5); let val: u8 = *boxed; ``` -再帰構造の作成: +再帰データ構造の作成: ```rust #[derive(Debug)] From 79268e553b4cbd3be5c9bc18c051cc10e940b186 Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:20:56 +0900 Subject: [PATCH 03/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index 40777e9..588c914 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -40,7 +40,7 @@ println!("{list:?}"); ``` 上記のプログラムの結果は`Cons(1, Cons(2, Nil))`となる。 -再帰構造にはBox化が必要である。例えば`Cons`を下記のように定義した場合コンパイルエラーとなる: +再帰データ構造にはBox化が必要である。例えば`Cons`を下記のように定義した場合コンパイルエラーとなる: ```rust Cons(T, List), From 09b268a4233b82f59ed16f58988e1f2ec95e860e Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:21:44 +0900 Subject: [PATCH 04/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index 588c914..02428ba 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -46,7 +46,7 @@ println!("{list:?}"); Cons(T, List), ``` -なぜなら`List`のスタックサイズはリスト内にどれだけのリストがあるかにより、このままでは`Cons`に対するスタックの割り当て量を把握できないためである。スタックサイズが決まっている[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)の導入により、`Cons`に必要なスタックサイズが把握できるようになる。 +なぜなら`List`のサイズはリスト内にどれだけのリストがあるかにより、このままでは`Cons`に対するスタックの割り当て量を把握できないためである。サイズが決まっている[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)の導入により、`Cons`に必要なスタックサイズが把握できるようになる。 ## メモリーレイアウト From 8e26fc71452302bd7c109b058740ae4c3133153c Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:22:27 +0900 Subject: [PATCH 05/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index 02428ba..ea1de48 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -56,7 +56,7 @@ Cons(T, List), これらの基本的なLayoutの要件に加えて、`Box`は有効な値`T`を示さなければならない。 -`T: Sized`である限り`Box`は単一のポインターであることを保証するとともにCのポインター(CのT*型)とのABI互換性を持つ。これはRustでCから呼び出す関数を作成する際に`Box`で定義したものがCでは`T*`になるという意味である。例として`Foo`の作成と破棄を行う関数を宣言するCのヘッダーをあげる: +`T: Sized`である限り`Box`は単一のポインターであることを保証するとともにCのポインター(CのT*型)とのABI互換性を持つ。これはRustでCから呼び出す関数を作成する際に`Box`で定義したものがCでは`T*`になるという意味である。例として`Foo`の作成と破棄を行う関数を宣言するCのヘッダーを示す: ```C /* C header */ From bc8346d2b2321d326e519b45f24b19f2ac966d5c Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:22:53 +0900 Subject: [PATCH 06/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index ea1de48..cf452cd 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -68,7 +68,7 @@ struct Foo* foo_new(void); void foo_delete(struct Foo*); ``` -この2つの関数はRustで下記のように実装できる。ここでは`struct Foo*`型に変換された`Box`は所有権の制約を補足する。`Box`が非ヌルであるため引数がヌルになる可能性のある`foo_delete`の引数はRustでは`Option>`になることに注意しなければならない。 +この2つの関数はRustで下記のように実装できる。ここでは`struct Foo*`型に変換された`Box`は所有権の制約を補足する。`Box`が非ヌルであるため、引数がヌルになる可能性のある`foo_delete`の引数はRustでは`Option>`になることに注意しなければならない。 ```rust #[repr(C)] From fc2600c848d6347955386e5a6a5d08be38806949 Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:23:05 +0900 Subject: [PATCH 07/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index cf452cd..9a7d6e4 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -129,5 +129,5 @@ for item in IntoIterator::into_iter(boxed_slice).enumerate() { | 名前 | 説明 | | --------------------------------------------------------------------------------- | ---------------------------------------- | -| [Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) | T 型のヒープを一意に所有するポインター型 | +| [Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) | ヒープに配置された T 型を一意に所有するポインター型 | | [ThinBox](https://doc.rust-lang.org/std/boxed/struct.ThinBox.html) (Experimental) | 薄い Box | \ No newline at end of file From 652aa9b44efbc89221f2bb7ac914e8791a5e8a65 Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:37:33 +0900 Subject: [PATCH 08/14] Update src/boxed/about.md Co-authored-by: hinshi <105423175+hinshiba@users.noreply.github.com> Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index 9a7d6e4..fb384ec 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -50,7 +50,7 @@ Cons(T, List), ## メモリーレイアウト -サイズが0でない値では、[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)はメモリー割り当てのため[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターを使用する。アロケーターとともに使用される[`Layout`](https://doc.rust-lang.org/std/alloc/struct.Layout.html)が適切な型であり、生ポインターがその型の有効な値を示す場合に、[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)と[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターに割り当てられた生ポインターは相互に変換できる。より詳しく言うと、[`Layout::for_value(&*value)`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value)とともに使用される[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターに割り当てられた`value: *mut T`は[`Box::::from_raw(value)`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.from_raw)を使用してBoxへと変換できる。逆に[`Box::::into_raw`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw)から得られた`value: *mut T`は[`Layout::for_value(&*value)`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value)と[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターによって解放できる。 +サイズが0でない値では、[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)はメモリー割り当てのため[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターを使用する。アロケーターの引数として使用される[`Layout`](https://doc.rust-lang.org/std/alloc/struct.Layout.html)が適切な型であり、生ポインターがその型の有効な値を示す場合に、[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)と[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターに割り当てられた生ポインターは相互に変換できる。より詳しく言うと、[`Layout::for_value(&*value)`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value)とともに使用される[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターに割り当てられた`value: *mut T`は[`Box::::from_raw(value)`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.from_raw)を使用してBoxへと変換できる。逆に[`Box::::into_raw`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw)から得られた`value: *mut T`は[`Layout::for_value(&*value)`](https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.for_value)と[`Global`](https://doc.rust-lang.org/std/alloc/struct.Global.html)アロケーターによって解放できる。 サイズが0の値では、`Box`は非ヌルでありアライメントされている必要がある。`Box::new`が使用できない場合にZST(ゼロサイズ型)のBoxを作成する推奨方法は[`ptr::NonNull::dangling`](https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling)を使用することである。 From 756c5fe91a6e154eb0add01676d52b058b63a48a Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:56:59 +0900 Subject: [PATCH 09/14] Update about.md Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index fb384ec..78a4191 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -6,7 +6,7 @@ Rust 1.0.0 ~ ## 概要 -`Box`はヒープアロケーションに分類される。 +`Box`はヒープアロケーションのための型である。 [`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)(単に ‘Box’ と呼ばれることもある)はRustにおいて一番単純なヒープアロケーションである。Boxはこのアロケーションの所有権を有し、スコープから外れる時に中身を破棄する。加えて、ヒープの割り当てが`isize::MAX`バイトを超えないことも保証する。 @@ -59,12 +59,12 @@ Cons(T, List), `T: Sized`である限り`Box`は単一のポインターであることを保証するとともにCのポインター(CのT*型)とのABI互換性を持つ。これはRustでCから呼び出す関数を作成する際に`Box`で定義したものがCでは`T*`になるという意味である。例として`Foo`の作成と破棄を行う関数を宣言するCのヘッダーを示す: ```C -/* C header */ +/* C ヘッダー */ -/* Returns ownership to the caller */ +/* 呼び出し元への所有権の返却 */ struct Foo* foo_new(void); -/* Takes ownership from the caller; no-op when invoked with null */ +/* 呼び出し元から所有権を取得; ヌルの場合何もしない */ void foo_delete(struct Foo*); ``` @@ -130,4 +130,4 @@ for item in IntoIterator::into_iter(boxed_slice).enumerate() { | 名前 | 説明 | | --------------------------------------------------------------------------------- | ---------------------------------------- | | [Box](https://doc.rust-lang.org/std/boxed/struct.Box.html) | ヒープに配置された T 型を一意に所有するポインター型 | -| [ThinBox](https://doc.rust-lang.org/std/boxed/struct.ThinBox.html) (Experimental) | 薄い Box | \ No newline at end of file +| [ThinBox](https://doc.rust-lang.org/std/boxed/struct.ThinBox.html) (Experimental) | 薄い Box | From 0060154c17d3593304d730d4e6acdf1ed6e57a28 Mon Sep 17 00:00:00 2001 From: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:03:47 +0900 Subject: [PATCH 10/14] Update about.md Signed-off-by: TANAKA Akinobu <89065984+tnk050@users.noreply.github.com> --- src/boxed/about.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boxed/about.md b/src/boxed/about.md index 78a4191..b0b33e3 100644 --- a/src/boxed/about.md +++ b/src/boxed/about.md @@ -46,7 +46,7 @@ println!("{list:?}"); Cons(T, List), ``` -なぜなら`List`のサイズはリスト内にどれだけのリストがあるかにより、このままでは`Cons`に対するスタックの割り当て量を把握できないためである。サイズが決まっている[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)の導入により、`Cons`に必要なスタックサイズが把握できるようになる。 +なぜなら`List`のサイズはリスト内にどれだけのリストがあるかにより、このままでは`Cons`に対するスタックの割り当て量を把握できないためである。サイズが決まっている[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)を用いることで、`Cons`に必要なスタックサイズが把握できるようになる。 ## メモリーレイアウト From 1222b3f6268a47d7347d65a397f000b3765c450b Mon Sep 17 00:00:00 2001 From: tnk Date: Fri, 13 Feb 2026 14:45:03 +0900 Subject: [PATCH 11/14] wip --- src/boxed/Box.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/boxed/Box.md diff --git a/src/boxed/Box.md b/src/boxed/Box.md new file mode 100644 index 0000000..3f21be9 --- /dev/null +++ b/src/boxed/Box.md @@ -0,0 +1,81 @@ +# 構造体 `std::boxed::Box` + +```rust +pub struct Box(/* private fields */) +where + A: std::alloc::Allocator, + T: ?Sized; +``` + +## バージョン + +Rust 1.0.0 ~ + +## 解説 + +`T`型のヒープアロケーションを一意に有するポインター型。 +詳細は[モジュールドキュメント](./about.md)を参照。 + +## 実装 + +### +```rust +impl Box +where + A: std::alloc::Allocator, +``` + +### `downcast` + +**Rust 1.0.0 ~** + +```rust +pub fn downcast(self) -> Result, Box> +where + T: Any, +``` + +Boxの中身をT型へ変換する関数。 + +```rust +use std::any::Any; + +fn print_if_string(value: Box) { + if let Ok(string) = value.downcast::() { + println!("String ({}): {}", string.len(), string); + } +} + +let my_string = "Hello World".to_string(); +print_if_string(Box::new(my_string)); // String (11): Hello World +print_if_string(Box::new(0i8)); // String に変換できないため何も表示されない +``` + +### `downcast_unchecked` + +```rust +pub unsafe fn downcast_unchecked(self) -> Box +where + T: Any, +``` +> [!NOTE] +> nightlyでのみ使用可能 + +Boxの中身をT型へ変換する関数。 +メモリー安全な代替は[`downcast`](#downcast)を参照 + +```rust +#![feature(downcast_unchecked)] + +use std::any::Any; + +let x: Box = Box::new(1_usize); + +unsafe { + assert_eq!(*x.downcast_unchecked::(), 1); +} +``` + +**安全性** + +Boxの中身はT型でなければならない。誤った型でこの関数を呼び出すと未定義動作となる。 From 1b7cc9f97f3a09222d5873320aa32ecbde38c1f9 Mon Sep 17 00:00:00 2001 From: tnk Date: Mon, 16 Feb 2026 14:22:49 +0900 Subject: [PATCH 12/14] wip --- src/boxed/Box.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/src/boxed/Box.md b/src/boxed/Box.md index 3f21be9..c66ba3f 100644 --- a/src/boxed/Box.md +++ b/src/boxed/Box.md @@ -18,7 +18,6 @@ Rust 1.0.0 ~ ## 実装 -### ```rust impl Box where @@ -35,7 +34,7 @@ where T: Any, ``` -Boxの中身をT型へ変換する関数。 +Boxの中身をT型へ変換することを試みる関数。 ```rust use std::any::Any; @@ -79,3 +78,129 @@ unsafe { **安全性** Boxの中身はT型でなければならない。誤った型でこの関数を呼び出すと未定義動作となる。 + +```rust +impl Box +where + A: Allocator, +``` +### `downcast` + +**Rust 1.0.0 ~** + +```rust +pub fn downcast(self) -> Result, Box> +where + T: Any, +``` + +Boxの中身をT型へ変換することを試みる関数。 + +```rust +use std::any::Any; + +fn print_if_string(value: Box) { + if let Ok(string) = value.downcast::() { + println!("String ({}): {}", string.len(), string); + } +} + +let my_string = "Hello World".to_string(); +print_if_string(Box::new(my_string)); +print_if_string(Box::new(0i8)); +``` + +### `downcast_unchecked` + +```rust +pub unsafe fn downcast_unchecked(self) -> Box +where + T: Any, +``` +> [!NOTE] +> nightlyでのみ使用可能 + +Boxの中身をT型へ変換する関数。 +メモリー安全な代替は[`downcast`](#downcast-1)を参照 + +```rust +#![feature(downcast_unchecked)] + +use std::any::Any; + +let x: Box = Box::new(1_usize); + +unsafe { + assert_eq!(*x.downcast_unchecked::(), 1); +} +``` + +**安全性** + +Boxの中身はT型でなければならない。誤った型でこの関数を呼び出すと未定義動作となる。 + +```rust +impl Box +``` + +**Rust 1.0.0 ~** + +### `new` + +```rust +pub fn new(x: T) -> Box +``` +ヒープ領域にメモリーを割り当て`x`を格納する。 +`T`がゼロサイズの場合、実際にはメモリーは割り当てられない。 + +```rust +let five = Box::new(5); +``` + +### `new_uninit` + +**Rust 1.82.0 ~** + +```rust +pub fn new_uninit() -> Box> +``` + +中身を初期化せずに新しいboxを作成する。 + +```rust +let mut five = Box::::new_uninit(); +// 遅延初期化: +five.write(5); +let five = unsafe { five.assume_init() }; + +assert_eq!(*five, 5) +``` + +### `new_zeroed` + +**Rust 1.92.0 ~** + +```rust +pub fn new_zeroed() -> Box> +``` + +初期化せずに新しいboxを作成し、中身を0バイトで埋める。 +このメソッドの正しい使用例と誤った使用例は[`MaybeUninit::zeroed`](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.zeroed)を参照。 + +```rust +let zero = Box::::new_zeroed(); +let zero = unsafe { zero.assume_init() }; + +assert_eq!(*zero, 0) +``` + +### `pin` + +**Rust 1.33.0 ~** + +```rust +pub fn pin(x: T) -> Pin> +``` + +新しい`Pin>`を作成する。`T`が[`Unpin`](https://doc.rust-lang.org/std/marker/trait.Unpin.html)を実装していない場合、`x`はメモリー内に固定され動かせなくなる。 +`Box`の作成と固定は2段階でも行え、`Box::pin(x)`は`Box::into_pin(Box::new(x))`と同じである。すでに`Box`がある場合や、[`Box::new`](#new)とは違った方法で(固定した)`Box`を作成したい場合は[`into_pin`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_pin)の使用を検討するとよい。 \ No newline at end of file From b2a709d75091d4cebdec12de0e8d258d42ba5f99 Mon Sep 17 00:00:00 2001 From: tnk Date: Tue, 3 Mar 2026 10:01:38 +0900 Subject: [PATCH 13/14] wip --- src/boxed/Box.md | 155 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 7 deletions(-) diff --git a/src/boxed/Box.md b/src/boxed/Box.md index c66ba3f..6b2366c 100644 --- a/src/boxed/Box.md +++ b/src/boxed/Box.md @@ -52,13 +52,14 @@ print_if_string(Box::new(0i8)); // String に変換できないため何も表 ### `downcast_unchecked` +> [!NOTE] +> nightlyでのみ使用可能 + ```rust pub unsafe fn downcast_unchecked(self) -> Box where T: Any, ``` -> [!NOTE] -> nightlyでのみ使用可能 Boxの中身をT型へ変換する関数。 メモリー安全な代替は[`downcast`](#downcast)を参照 @@ -79,6 +80,7 @@ unsafe { Boxの中身はT型でなければならない。誤った型でこの関数を呼び出すと未定義動作となる。 + ```rust impl Box where @@ -112,13 +114,14 @@ print_if_string(Box::new(0i8)); ### `downcast_unchecked` +> [!NOTE] +> nightlyでのみ使用可能 + ```rust pub unsafe fn downcast_unchecked(self) -> Box where T: Any, ``` -> [!NOTE] -> nightlyでのみ使用可能 Boxの中身をT型へ変換する関数。 メモリー安全な代替は[`downcast`](#downcast-1)を参照 @@ -139,6 +142,7 @@ unsafe { Boxの中身はT型でなければならない。誤った型でこの関数を呼び出すと未定義動作となる。 + ```rust impl Box ``` @@ -165,7 +169,7 @@ let five = Box::new(5); pub fn new_uninit() -> Box> ``` -中身を初期化せずに新しいboxを作成する。 +ヒープ上の中身を初期化せずに新しいboxを作成する。 ```rust let mut five = Box::::new_uninit(); @@ -202,5 +206,142 @@ assert_eq!(*zero, 0) pub fn pin(x: T) -> Pin> ``` -新しい`Pin>`を作成する。`T`が[`Unpin`](https://doc.rust-lang.org/std/marker/trait.Unpin.html)を実装していない場合、`x`はメモリー内に固定され動かせなくなる。 -`Box`の作成と固定は2段階でも行え、`Box::pin(x)`は`Box::into_pin(Box::new(x))`と同じである。すでに`Box`がある場合や、[`Box::new`](#new)とは違った方法で(固定した)`Box`を作成したい場合は[`into_pin`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_pin)の使用を検討するとよい。 \ No newline at end of file +新しい`Pin>`を作成する。`T`が[`Unpin`](https://doc.rust-lang.org/std/marker/trait.Unpin.html)を実装していない場合、`x`はメモリー上に固定され動かせなくなる。 +`Box`の作成と固定は2段階でも行え、`Box::pin(x)`は`Box::into_pin(Box::new(x))`と同じである。すでに`Box`がある場合や、[`Box::new`](#new)とは違った方法で(固定した)`Box`を作成したい場合は[`into_pin`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_pin)の使用を検討するとよい。 + +### `try_new` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn try_new(x: T) -> Result, AllocError> +``` + +ヒープにメモリーを割り当ててから`x`を格納する。割り当てに失敗した場合はエラーを返す。 +`T`がゼロサイズの場合、実際にはメモリーは割り当てられない。 + +```rust +#![feature(allocator_api)] + +let five = Box::try_new(5)?; +``` + +### `try_new_uninit` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn try_new_uninit() -> Result>, AllocError> +``` + +ヒープ上の中身を初期化せずに新しいboxを作成する。割り当てに失敗した場合はエラーを返す。 + +```rust +#![feature(allocator_api)] + +let mut five = Box::::try_new_uninit()?; +// Deferred initialization: +five.write(5); +let five = unsafe { five.assume_init() }; + +assert_eq!(*five, 5); +``` + +### try_new_zeroed + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn try_new_zeroed() -> Result>, AllocError> +``` + +初期化せずに新しいboxを作成し、中身を0バイトで埋める。 +このメソッドの正しい使用例と誤った使用例は[`MaybeUninit::zeroed`](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.zeroed)を参照。 + +```rust +#![feature(allocator_api)] + +let zero = Box::::try_new_zeroed()?; +let zero = unsafe { zero.assume_init() }; + +assert_eq!(*zero, 0); +``` + +### map + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn map(this: Box, f: impl FnOnce(T) -> U) -> Box +``` + +boxの中身を与えられた関数より再配置する。可能なら割り当てを再利用する。 +`f`はbox内の値に対して呼び出され、返り値もbox化される。 +注意: これは関連関数である、つまり`b.map(f)`の代わりに`Box::map(b, f)`と呼び出さなければならない。これは中身の型のメソッドと衝突しないようにするためである。 + +```rust +#![feature(smart_pointer_try_map)] + +let b = Box::new(7); +let new = Box::map(b, |i| i + 7); +assert_eq!(*new, 14); +``` + +### try_map + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn try_map( + this: Box, + f: impl FnOnce(T) -> R, +) -> <::Residual as Residual::Output>>>::TryType +where + R: Try, + ::Residual: Residual::Output>>, +``` + +boxの中身を与えられた関数より再配置することを試みる。可能なら割り当てを再利用する。 +`f`はbox内の値に対して呼び出され、返り値もbox化される。 +注意: これは関連関数である、つまり`b.map(f)`の代わりに`Box::map(b, f)`と呼び出さなければならない。これは中身の型のメソッドと衝突しないようにするためである。 + +```rust +#![feature(smart_pointer_try_map)] + +let b = Box::new(7); +let new = Box::try_map(b, u32::try_from).unwrap(); +assert_eq!(*new, 7); +``` + +```rust +impl Box +where + A: Allocator, +``` + +### new_in + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn new_in(x: T, alloc: A) -> Box +where + A: Allocator, +``` + +与えられたアロケーターからメモリーを割り当て`x`を格納する。 +`T`がゼロサイズの場合、実際にはメモリーは割り当てられない。 + +```rust +#![feature(allocator_api)] + +use std::alloc::System; + +let five = Box::new_in(5, System); +``` \ No newline at end of file From b1e37547d4cf510e6e8178ba07951723e2d884e7 Mon Sep 17 00:00:00 2001 From: tnk Date: Thu, 12 Mar 2026 11:07:00 +0900 Subject: [PATCH 14/14] wip --- src/boxed/Box.md | 220 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 12 deletions(-) diff --git a/src/boxed/Box.md b/src/boxed/Box.md index 6b2366c..2affcf1 100644 --- a/src/boxed/Box.md +++ b/src/boxed/Box.md @@ -155,7 +155,7 @@ impl Box pub fn new(x: T) -> Box ``` ヒープ領域にメモリーを割り当て`x`を格納する。 -`T`がゼロサイズの場合、実際にはメモリーは割り当てられない。 +`T`がゼロサイズ型の場合、実際にはメモリーは割り当てられない。 ```rust let five = Box::new(5); @@ -169,7 +169,7 @@ let five = Box::new(5); pub fn new_uninit() -> Box> ``` -ヒープ上の中身を初期化せずに新しいboxを作成する。 +中身を初期化せずに新しいboxを作成する。 ```rust let mut five = Box::::new_uninit(); @@ -188,7 +188,7 @@ assert_eq!(*five, 5) pub fn new_zeroed() -> Box> ``` -初期化せずに新しいboxを作成し、中身を0バイトで埋める。 +中身を初期化せずに新しいboxを作成し、中身を0バイトで埋める。 このメソッドの正しい使用例と誤った使用例は[`MaybeUninit::zeroed`](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.zeroed)を参照。 ```rust @@ -218,8 +218,8 @@ pub fn pin(x: T) -> Pin> pub fn try_new(x: T) -> Result, AllocError> ``` -ヒープにメモリーを割り当ててから`x`を格納する。割り当てに失敗した場合はエラーを返す。 -`T`がゼロサイズの場合、実際にはメモリーは割り当てられない。 +ヒープにメモリーを割り当ててから`x`を格納し、割り当てに失敗した場合エラーを返す。 +`T`がゼロサイズ型の場合、実際にはメモリーは割り当てられない。 ```rust #![feature(allocator_api)] @@ -236,7 +236,7 @@ let five = Box::try_new(5)?; pub fn try_new_uninit() -> Result>, AllocError> ``` -ヒープ上の中身を初期化せずに新しいboxを作成する。割り当てに失敗した場合はエラーを返す。 +中身を初期化せずに新しいboxを作成し、割り当てに失敗した場合エラーを返す。 ```rust #![feature(allocator_api)] @@ -249,7 +249,7 @@ let five = unsafe { five.assume_init() }; assert_eq!(*five, 5); ``` -### try_new_zeroed +### `try_new_zeroed` > [!NOTE] > nightlyでのみ使用可能 @@ -258,7 +258,7 @@ assert_eq!(*five, 5); pub fn try_new_zeroed() -> Result>, AllocError> ``` -初期化せずに新しいboxを作成し、中身を0バイトで埋める。 +中身を初期化せずに新しいboxを作成し、ヒープ上のメモリーを0バイトで埋める。割り当てに失敗した場合エラーを返す。 このメソッドの正しい使用例と誤った使用例は[`MaybeUninit::zeroed`](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.zeroed)を参照。 ```rust @@ -270,7 +270,7 @@ let zero = unsafe { zero.assume_init() }; assert_eq!(*zero, 0); ``` -### map +### `map` > [!NOTE] > nightlyでのみ使用可能 @@ -291,7 +291,7 @@ let new = Box::map(b, |i| i + 7); assert_eq!(*new, 14); ``` -### try_map +### `try_map` > [!NOTE] > nightlyでのみ使用可能 @@ -324,7 +324,7 @@ where A: Allocator, ``` -### new_in +### `new_in` > [!NOTE] > nightlyでのみ使用可能 @@ -336,7 +336,7 @@ where ``` 与えられたアロケーターからメモリーを割り当て`x`を格納する。 -`T`がゼロサイズの場合、実際にはメモリーは割り当てられない。 +`T`がゼロサイズ型の場合、実際にはメモリーは割り当てられない。 ```rust #![feature(allocator_api)] @@ -344,4 +344,200 @@ where use std::alloc::System; let five = Box::new_in(5, System); +``` + +### `try_new_in` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn try_new_in(x: T, alloc: A) -> Result, AllocError> +where + A: Allocator, +``` + +与えられたアロケーターからメモリーを割り当て`x`を格納し、割り当てに失敗した場合エラーを返す。 +`T`がゼロサイズ型の場合、実際にはメモリーは割り当てられない。 + +```rust +#![feature(allocator_api)] + +use std::alloc::System; + +let five = Box::try_new_in(5, System)?; +``` + +### `new_uninit_in` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn new_uninit_in(alloc: A) -> Box, A> +where + A: Allocator, +``` + +与えられたアロケーターから中身を初期化せずに新しいboxを作成する。 + +```rust +#![feature(allocator_api)] + +use std::alloc::System; + +let mut five = Box::::new_uninit_in(System); +// Deferred initialization: +five.write(5); +let five = unsafe { five.assume_init() }; + +assert_eq!(*five, 5) +``` + +### `try_new_uninit_in` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> +where + A: Allocator, +``` + +与えられたアロケーターから中身を初期化せずに新しいboxを作成し、割り当てに失敗した場合エラーを返す。 + +```rust +#![feature(allocator_api)] + +use std::alloc::System; + +let mut five = Box::::try_new_uninit_in(System)?; +// 遅延初期化: +five.write(5); +let five = unsafe { five.assume_init() }; + +assert_eq!(*five, 5); +``` + +### `new_zeroed_in` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn new_zeroed_in(alloc: A) -> Box, A> +where + A: Allocator, +``` + +与えられたアロケーターから中身を初期化せずに新しいboxを作成し、ヒープ上のメモリーを0バイトで埋める。割り当てに失敗した場合エラーを返す。 +このメソッドの正しい使用例と誤った使用例は[`MaybeUninit::zeroed`](https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.zeroed)を参照。 + +```rust +#![feature(allocator_api)] + +use std::alloc::System; + +let zero = Box::::try_new_zeroed_in(System)?; +let zero = unsafe { zero.assume_init() }; + +assert_eq!(*zero, 0); +``` + +### `pin_in` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn pin_in(x: T, alloc: A) -> Pin> +where + A: 'static + Allocator, +``` + +新しい`Pin>`を作成する。`T`が[`Unpin`](https://doc.rust-lang.org/std/marker/trait.Unpin.html)を実装していない場合、`x`はメモリー上に固定され動かせなくなる。 +`Box`の作成と固定は2段階でも行え、`Box::pin_in(x, alloc)`は`Box::into_pin(Box::new_in(x, alloc))`と同じである。すでに`Box`がある場合や、[`Box::new_in`](#new_in)とは違った方法で(固定した)`Box`を作成したい場合は[`into_pin`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_pin)の使用を検討するとよい。 + +### `into_boxed_slice` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn into_boxed_slice(boxed: Box) -> Box<[T], A> +``` + +`Box`を`Box<[T]>`へ変換する。 +変換にあたってヒープの割り当てはされずその場所で行われる。 + +### `into_inner` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn into_inner(boxed: Box) -> T +``` + +`Box`を消費して中身の値を返す。 + +```rust +#![feature(box_into_inner)] + +let c = Box::new(5); + +assert_eq!(Box::into_inner(c), 5); +``` + +### `take` + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn take(boxed: Box) -> (T, Box, A>) +``` + +メモリーの割り当てを消費せずに`Box`を消費し、中身の値と値が入っていた領域が未初期化の状態の`Box`を返す。 +[`write`](#write)とともに使用することでboxと割り当てを再利用することができる。 + + +```rust +#![feature(box_take)] + +let c = Box::new(5); + +// boxから値を取り出す +let (value, uninit) = Box::take(c); +assert_eq!(value, 5); + +// 別の値のためにboxを再利用する +let c = Box::write(uninit, 6); +assert_eq!(*c, 6); +``` + + +```rust +impl Box +where + T: CloneToUninit + ?Sized, +``` + +### clone_from_ref + +> [!NOTE] +> nightlyでのみ使用可能 + +```rust +pub fn clone_from_ref(src: &T) -> Box +``` + +ヒープ上にメモリーを割り当て複製した`src`を格納する。 +`src`がゼロサイズの場合、実際にはメモリーは割り当てられない。 + +```rust +#![feature(clone_from_ref)] + +let hello: Box = Box::clone_from_ref("hello"); ``` \ No newline at end of file