Rustはライフタイムに厳しく、また複雑なため説明が丁寧でも対処法がわかりづらいことが多いです。
私は次のような状況での解決方法がついに分かったため、備忘録としても、また今回のケースにぴったりの解決法が調べても出てこなかったため残します。
簡単な例として、シューティングゲームのエネミーが弾のテクスチャと自身の発射した弾の配列を持っているとします。
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));
}
}
このコードの場合次のようなエラーになります。
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src\main.rs:15:30
|
15 | self.bullets.push(Bullet(&self.bullet_texture));
| ^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 14:3...
--> src\main.rs:14:3
|
14 | / fn shot(&mut self) {
15 | | self.bullets.push(Bullet(&self.bullet_texture));
16 | | }
| |___^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:15:30
|
15 | self.bullets.push(Bullet(&self.bullet_texture));
| ^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 10:6...
--> src\main.rs:10:6
|
10 | impl<'a> Enemy<'a> {
| ^^
= note: ...so that the expression is assignable:
expected Bullet<'a>
found Bullet<'_>
.....。なんとなく言ってることはわかるのですが、これを読んでもすぐに対処法が思いつきそうにはありません。
最初、BulletのライフタイムはEnemyと同じかそれより短いので、弾が持つEnemyのフィールドへの参照がより長く生存することはないと思い、このエラーの原因がずっとわかりませんでした。
ただ問題点はそこではなかったようで、次のようにコードを変えるとエラーが出なくなります。
fn shot(&'a mut self) { // lifetime parameter
self.bullets.push(Bullet(&self.bullet_texture));
}
(ここからは自論です。違っているかもしれません。)
先ほどのエラー内容の最初、anonymous lifetime #1
という表現がありましたが、これは&mut self
に与えられる参照のライフタイムのことです。
Enemy
構造体の定義時にいくつかライフタイムを与えましたが、それらが示すのは、「Enemy.bullets
配列が持つ参照のライフタイムとEnemy
のライフタイムは同じ」というものでした。
しかし最初のコードではshot()
に与えられる参照(&mut self
)のライフタイムが明示されていなかったため、&self.bullet_texture
のライフタイムとの関係性が不明なままでした。これが原因だと思います。
なので、&'a mut self
とすることで回避できた...ということだと思います。
もっと詳しく解説していただける方がいらっしゃいましたらコメントなどくださると幸いです。