【问题标题】:Why is the lifetime of my returned impl Trait restrained to the lifetime of its input?为什么我返回的 impl Trait 的生命周期限制在其输入的生命周期内?
【发布时间】:2022-11-22 19:00:47
【问题描述】:

为了弄清楚为什么我的某些代码无法编译,我创建了以下最小测试。

我正在尝试编写一个函数,它接收类似 &Vec<i32> 的内容并返回可以通过 i32 转换为 Iterator 的内容。

输出不包含任何从输入借来的东西。我的意图是输出比输入具有更长的生命周期。

在我的新手看来,这看起来应该可行。

fn error_1<'a, I: IntoIterator<Item=&'a i32>>(_: I) -> impl IntoIterator<Item=i32> + 'static {
    vec![1]
}

但是,当我测试输出是否可以比输入更长寿时......

fn test_e1() {
    let v = vec![3];
    let a = error_1(&v);
    drop(v); // DROP v BEFORE a.. should be ok!?
}

我收到这个错误。

error[E0505]: cannot move out of `v` because it is borrowed
 --> src/lib.rs:8:10
  |
7 |     let a = error_1(&v);
  |                     -- borrow of `v` occurs here
8 |     drop(v); // DROP v BEFORE a.. should be ok!?
  |          ^ move out of `v` occurs here
9 | }
  | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl IntoIterator<Item = i32>`

好的 - 所以,rust 担心 IntoIterator 的可能实现可能借了“v”?
Playground Link - broken code
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=41ef3bce0157cc23f824f20eb0651bd9

我试着进一步试验这个......
绝对让我感到困惑的是,为什么下一个测试编译得很好......它似乎有同样的问题,但 rust 很乐意编译它。

fn fine_1<'a, I: IntoIterator<Item=i32>>(_: &I) -> impl IntoIterator<Item=i32> + 'static {
    vec![1]
}

fn test_f1() {
    let v = vec![3];
    let a = fine_1(&v);
    drop(v); // DROP v BEFORE a.. should be ok!?
}

Playground link for tweaked, working code
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7e92549aa4e741c4dd0aae289afcf9db

有人可以帮我解释一下第一个代码有什么问题吗?
我如何指定返回类型的生命周期与参数的生命周期完全无关?

只是为了好玩,另一个错误的例子..这次返回与 Vec 无关的东西..同样的错误。

    fn error_fn<'a, I: IntoIterator<Item=&'a i32>>(_: I) -> impl Fn() + 'static{
        || {}
    }

    fn test_fn() {
        let v = vec![3];
        let a = error_fn(&v);
        drop(v);
    }

我不想解决这个问题……我可以重构代码。
这里的目标是学习......这暴露了我对生命时间理解的差距......
直到最近,我还以为我已经搞定了:D

值得一提的是,如果我将输入更改为具体类型,而不是 trait impl.. `_: &Vec 一切,再次编译正常。

它似乎是特征相关类型的生命周期,打破了一切......我只是不明白为什么!??

【问题讨论】:

    标签: rust traits lifetime-scoping


    【解决方案1】:

    您在这里遇到了生命周期省略,您的第一个实现大致相当于以下显式版本:

    fn error_1<'b, 'a, I: IntoIterator<Item=&'a i32> + 'b> (_: I)
        -> impl IntoIterator<Item=i32> + 'b
    {
        vec![1]
    }
    

    这解释了为什么它保留借用以及为什么使用 'static 的显式注释有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多