以下のコードを実行すると、
use futures::Future;
fn main() {
let expected = 101;
let actual = A { n: 1 }.fut_add_100().wait().unwrap();
assert_eq!(actual, expected);
}
struct A {
n: i32,
}
impl A {
fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> {
self.fut_100().map(|n_100| self.n + n_100) // FIXME: cannot infer an appropriate lifetime ...but this borrow...
}
fn fut_100(&self) -> impl Future<Item = i32, Error = ()> {
futures::future::ok(100)
}
}
コンパイルエラーになります。
error: cannot infer an appropriate lifetime
--> src/main.rs:12:28
|
11 | fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> {
| ----------------------------------- this return type evaluates to the `'static` lifetime...
12 | self.fut_100().map(|n_100| self.n + n_100)
| ^^^^^^^^^^^^^^^^^^^^^^ ...but this borrow...
|
note: ...can't outlive the anonymous lifetime #1 defined on the method body at 11:5
--> src/main.rs:11:5
|
11 | / fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> {
12 | | self.fut_100().map(|n_100| self.n + n_100)
13 | | }
| |_____^
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 11:5
|
11 | fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
なぜかというと、関数 (追記: コメント欄参照)fut_100
が self
の参照を取得している式文が終わっていないのに、さらに self.n
で self
を参照しようとしているからです。(自信なし)
さて、以下のように変更するとコンパイルエラーは解消します。
(追記: 変数名を _n
から m
に変更しました。)
diff --git src/main.rs src/main.rs
index 11ec4d1..e9f747a 100644
--- src/main.rs
+++ src/main.rs
@@ -9,7 +9,8 @@ struct A {
}
impl A {
fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> {
- self.fut_100().map(|n_100| self.n + n_100)
+ let m = self.n;
+ self.fut_100().map(move |n_100| m + n_100)
}
fn fut_100(&self) -> impl Future<Item = i32, Error = ()> {
ポイントは以下の 2 つです。
- 外側でいったん
self.n
を変数にコピーしておく。 -
move
クロージャを使う。(追記: コメントや https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/closures.html#move-クロージャ 等参照)
以上です。今となっては単純な話だったなと思いますが、当時の実際のコードはやけに複雑だったりして解決にかなり手間取りました。
(以下追記)
statiolake さんの補足してくださった、明示的にライフタイムを指定する修正方法の方が
- 変数
let m = self.n;
の際のm
へのコピーが減る。- 今回の場合は
i32
なのであんまり気になりませんが、当時の実際のコードでは構造体をclone
していました。
- 今回の場合は
- 修正方法がエラーメッセージの
cannot infer an appropriate lifetime
に対応している。
という点で望ましく感じています。
- fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> {
- self.fut_100().map(|n_100| self.n + n_100)
+ fn fut_add_100<'a>(&'a self) -> impl Future<Item = i32, Error = ()> + 'a {
+ self.fut_100().map(move |n_100| self.n + n_100)
や
- fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> {
- self.fut_100().map(|n_100| self.n + n_100)
+ fn fut_add_100(&self) -> impl Future<Item = i32, Error = ()> + '_ {
+ self.fut_100().map(move |n_100| self.n + n_100)
のような修正方法です。