LoginSignup
2
0

More than 3 years have passed since last update.

Future 使用時のコンパイルエラー "cannot infer an appropriate lifetime"

Last updated at Posted at 2019-10-18

以下のコードを実行すると、

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_100self の参照を取得している式文が終わっていないのに、さらに self.nself を参照しようとしているからです。(自信なし) (追記: コメント欄参照)

さて、以下のように変更するとコンパイルエラーは解消します。

(追記: 変数名を _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 つです。

  1. 外側でいったん self.n を変数にコピーしておく。
  2. 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)

のような修正方法です。

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0