Rustの”ポインタ”は内部的には2個までらしい

Rustを書く練習をしていた際に教えてもらいました。

## 疑問
ある日、Rustを書く練習をしていると、こんなエラーが出ました。

```.stderr
error[E0277]: the size for values of type `Self` cannot be known at compilation time
 --> src/lib.rs:8:9
  |
8 |         self
  |         ^^^^ doesn't have a size known at compile-time
  |
  = note: required for the cast from `Box<Self>` to `Box<(dyn State + 'static)>`
help: consider further restricting `Self`
  |
7 |     fn request_review(self: Box<Self>) -> Box<dyn State> where Self: Sized {
  |                                                       +++++++++++++++++
```

なるほど...まてよ、`doesn't have a size known at compile-time`？？
`self`は`Box<Self>`としてポインタの背後にいるのだからサイズはわかるのでは...?

## サイズ不明の謎
謎だったので[Discord](https://discord.com/invite/rust-lang-community)で聞いてみると、こんな趣旨の返答をくれた方がいました。
曰く、「`fat pointer`は`extra fat`にはなれないからキャストができずエラーが出ている」とのこと。
調べてみると、`fat pointer`とは、データへのポインタと同時にそのメタデータも保持しているポインタのことらしいです。
例はスライスで、例えば`[u8]`は(ポインタ、長さ）の二つを包含しています。

しかし、`extra fat`とは...?（ポインタ、長さ）へのポインタを保持すればいくらでも太れるはず...

## ポインタは2個まで？
これも聞いてみると、「Rustの"ポインタ"は**1つか2つのポインタ**しか持てないから無理」とのことでした。
どうやら、今回のコードで使っていたトレイトオブジェクトには`(データへのポインタ, vtableポインタ)`の二つが必要だったようで、そこに元のメタデータを加えるとポインタが3つになってしまうことがエラーの原因だったようです。
また、前述のポインタを保持するポインタは`Box<Box<Self>>`のように`Box`を二重にかければ作れますが、また別の話だそう。

2024/9/15追記：
保持するポインタが１つのポインタは「痩せた」(thin)ポインタ、２つのポインタは「太った」(fat)ポインタと呼ばれるようです。

## 資料
### 実際のコードおよびエラー
元ネタは[The Rust Programming Languageの第17章3節](https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html)[^1]です。

[^1]: 英語版です。dynキーワードが追加される前の古い記法を使っていますが、[日本語版もあります](https://doc.rust-jp.rs/book-ja/ch17-03-oo-design-patterns.html)。
コード：

```rust: lib.rs
// ブログ記事風の構造体
// the bookのお題がトレイトオブジェクトを使った状態管理なので
// stateフィールドを設けている
struct Post {
    state: Box<dyn State>,
    content: String,
}

// 状態管理用のトレイト
trait State {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        // ここがエラー：コンパイル時にサイズが不明
        self
    }
}

// 下書き「状態」
struct Draft {}
impl State for Draft {}

fn main() {
    let mut p = Post {
        state: Box::new(Draft {}),
        content: String::new(),
    };
    p.state = p.state.request_review();
}
```
エラー（再掲）：
```.stderr
error[E0277]: the size for values of type `Self` cannot be known at compilation time
  --> src/main.rs:13:9
   |
13 |         self
   |         ^^^^ doesn't have a size known at compile-time
   |
   = note: required for the cast from `Box<Self>` to `Box<(dyn State + 'static)>`
help: consider further restricting `Self`
   |
11 |     fn request_review(self: Box<Self>) -> Box<dyn State> where Self: Sized {
   |                                                          +++++++++++++++++
```

### 解決策
コンパイラが言う通り`Self: Sized + 'static`を指定すれば良かったようです。ただ、これをやると別のエラーが出ます：
```.stderr
error: the `request_review` method cannot be invoked on a trait object
  --> src/main.rs:28:23
   |
12 |     where Self: Sized + 'static
   |                 ----- this has a `Sized` requirement
...
28 |     p.state = p.state.request_review();
   |                       ^^^^^^^^^^^^^^
```
トレイトオブジェクトは`Sized`でないと怒られます。

よって、トレイトでデフォルト実装を提供しないと言う方法が一番早いと思います。ただ、記述量がトレイトを実装する型の数に比例して増えるため、原著のように型システムを使う方向に進みたくなります。
```rust: lib.rs
// ブログ記事風の構造体
// the bookのお題がトレイトオブジェクトを使った状態管理なので
// stateフィールドを設けている
struct Post {
    state: Box<dyn State>,
    content: String,
}

// 状態管理用のトレイト
trait State {
    // デフォルト実装無し
    fn request_review(self: Box<Self>) -> Box<dyn State>; 
}

// 下書き「状態」
struct Draft {}
impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        // こうするとエラーがなくなる
        // おそらく型推論されてSizedだとわかるため
        self
    }
}

fn main() {
    let mut p = Post {
        state: Box::new(Draft {}),
        content: String::new(),
    };
    p.state = p.state.request_review();
}
```