自己参照構造体は作ることが出来ない

Qiitaからのメモ

【Rust】構造体に自身のフィールドの参照の配列を持たせる方法 - Qiita

struct Bullet<'a>(&'a Texture);

struct Enemy<'a> {
  bullet_texture: Texture,
  bullets: Vec<Bullet<'a>>
}

impl<'a> Enemy<'a> {
  fn new(bullet_texture: Texture) -> Self {
    Enemy { bullet_texture, bullets: vec![] }
  }
  fn shot(&mut self) {
    self.bullets.push(Bullet(&self.bullet_texture));
  }
}

回答

https://qiita.com/9laceef/items/aa0d7e1bd5041a1857d5#comment-40efdbbd19675bae1ab3

コメントがついていますが補足します。自己参照構造体はRustでは基本的にはできないです。 ライフタイムだけの問題ではなく、参照が無効になってしまうケースがあるのです。 Rustでは値の場所が変わりうるのでデータ型が移動したら参照が無効になってしまいます。 例えば以下のコードがもし動くとしたら、

fn main() {
    let mut enemy = Enemy::new(Texture);
    enemy.shot();
    let enemy2 = enemy;
}
+----------------------+
|                      |
|  enemy               |
|  +-------+---------+---------+
|  | Enemy | texture | bullets |
|  +-------+---------+---------+
|            ^
|      +-----+
|      |
|  +--------+
+->| bullet | Vecの中身
   +--------+

それが let enemy2 = enemy とするとenemyがムーブするので元あったenemyの領域が無効になります。その結果以下のような無効なメモリ領域を指すBulletが出来上がってしまいます。

   enemyの残骸
   +-------+---------+---------+
   | xxxxxxxxxxxxxxxxxxxxxxxxx |
   +-------+---------+---------+
             ^
       +-----+
       |
   +--------+
+->| bullet | Vecの中身
|  +--------+
|
+------------------------+
   enemy2                |
   +-------+---------+---------+
   | Enemy | texture | bullets |
   +-------+---------+---------+


enemy1の生成

f:id:yossan2:20210303233503p:plain
enemy1

enemy2 = enemy1 あと 参照とはフィールドのアドレスを渡すことであることがわかる

f:id:yossan2:20210303233551p:plain
enemy2