この事象を理解するためには、ライフタイム省略規則について知っておく必要があります.
詳細は The Rust Programming Language 日本語版 10.3 ライフタイムで参照を検証する の「ライフタイム省略」をご自身で読んで確認していただきたいですが、重要な部分だけ引用します.
最初の規則は、参照である各引数は、独自のライフタイム引数を得るというものです。換言すれば、 1引数の関数は、1つのライフタイム引数を得るということです: fn foo<'a>(x: &'a i32); 2つ引数のある関数は、2つの個別のライフタイム引数を得ます: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); 以下同様。
2番目の規則は、1つだけ入力ライフタイム引数があるなら、そのライフタイムが全ての出力ライフタイム引数に代入されるというものです: fn foo<'a>(x: &'a i32) -> &'a i32。
3番目の規則は、複数の入力ライフタイム引数があるけれども、メソッドなのでそのうちの一つが&selfや&mut selfだったら、 selfのライフタイムが全出力ライフタイム引数に代入されるというものです。 この3番目の規則により、必要なシンボルの数が減るので、メソッドが遥かに読み書きしやすくなります。
今回の例で言えば、set
関数は、1番目の規則によって以下のようになり、
rust
1pub fn set<'a>(&'a mut self, num: i32)-> Result<(), &str> {}
さらに2番目の規則によって、以下のようなライフタイムを持った関数だと解釈されます.
rust
1pub fn set<'a>(&'a mut self, num: i32)-> Result<(), &'a str> {}
func
関数も同様に考えてみましょう.一旦疑似コードで表してみます.
rust
1// 疑似コードなのでコンパイルできません
2pub fn func<'a>(&'a mut self) -> Result<(), &'a str> {
3 Element::set::<'b>(&'b mut self.field[0], 0)?;
4 Element::set::<'c>(&'c mut self.field[0], 1)?;
5 Ok(())
6}
ここで、&mut self
の制約からは、'b
,'c
は'a
より決して長くならないことが言えます.逆に、&str
の制約からは、'b
,'c
が'a
より長くなる必要があることが言えます.そしてこれらを合わせると'a
='b
='c
となります.しかしこれでは、同じライフタイムを持った可変参照が同時に存在するので、借用規則に反しておりコンパイルエラーになるというわけです.
根本的な原因は、返り値のライフタイムが不当に狭くなっていることなので、今回であれば以下のようにライフタイムを'static
にすれば、コンパイルエラーは解消します.
rust
1struct Element {
2 element: i32,
3}
4impl Element {
5 pub fn set(&mut self, num: i32) -> Result<(), &'static str> {
6 if num == 0 {
7 return Err("えらー");
8 }
9 self.element = num;
10 Ok(())
11 }
12}
13
14struct Field {
15 field: [Element; 10],
16}
17impl Field {
18 pub fn func(&mut self) -> Result<(), &'static str> {
19 self.field[0].set(1)?;
20 self.field[0].set(1)?;
21 Ok(())
22 }
23}
'static
にできない場合は、おとなしくString
を返した方が楽だと思います(特に初心者のうちは).
?演算子を使わなければエラーが出ない
おそらくこれは勘違いじゃないかなと.
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/26 01:30