【问题标题】:Rust: error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements in closureRust:错误[E0495]:由于关闭时的冲突要求,无法推断自动引用的适当生命周期
【发布时间】:2020-05-18 15:51:37
【问题描述】:

原始想法

在我的一个虚拟项目中,我想使用循环迭代器(例如生成整数)。

use std::iter::Cycle;

type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;

fn generate_cycles() -> [IntegerCycle; 2] {
  let mut cycles = [
    [1, 2].iter().cycle(),
    [2, 4].iter().cycle(),
  ];

  cycles
}


fn main() {
  let mut cycles = generate_cycles();
  // ...
}

重构

虽然前面的代码按预期工作,但我的实际示例有点复杂,因此我希望调整 generate_cycles 函数以能够执行更多操作(在以下示例中,乘以 2 ,然后生成循环迭代器)。 为此,我尝试使用arraymap:

extern crate arraymap;

use arraymap::ArrayMap;
use std::iter::Cycle;

type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;

fn generate_cycles() -> [IntegerCycle; 2] {
  let mut cycles = [
    [1, 2],
    [2, 4],
  ];

  cycles
    .map(|points| {
      points.map(|point| point*2)
    })
    .map(|points| {
      points.iter().cycle()
    })
}


fn main() {
  let mut cycles = generate_cycles();
  // ...
}

问题

上述解决方案不起作用,而且,作为一个 Rust 初学者,最近接触了“生命周期”的概念,我不明白为什么编译器在这里抱怨,或者我能做些什么让他开心。

error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements
  --> src/main.rs:20:14
   |
20 |       points.iter().cycle()
   |              ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 19:10...
  --> src/main.rs:19:10
   |
19 |       .map(|points| {
   |  __________^
20 | |       points.iter().cycle()
21 | |     })
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:20:7
   |
20 |       points.iter().cycle()
   |       ^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected [std::iter::Cycle<std::slice::Iter<'static, i32>>; 2]
              found [std::iter::Cycle<std::slice::Iter<'_, i32>>; 2]

这是一个 REPL,代码尝试使用 arraymap: https://repl.it/repls/ShadowyStrikingFirm

【问题讨论】:

    标签: rust closures lifetime


    【解决方案1】:

    在你的类型声明中:

    type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
    

    您说用于构建迭代器的底层切片必须具有'static 生命周期,也就是说,它们必须永远存在。然后你使用像 [1, 2] 这样的文字数组,就像所有文字一样,有 'static' 生命周期并且一切顺利:

    let r: &'static [i32; 2] = &[1, 2]; //Ok
    

    但是,您尝试使用类似于以下更简单的代码:

    let a = [1, 2].map(|x| 2 * x);
    let r: &'static [i32; 2] = &a; //error: borrowed value does not live long enough
    

    那是arraymap::map 的结果是一个普通的数组,而不是一个字面量的数组,所以它没有'static 的生命周期。它不能是静态的,因为您是在运行时计算值。只要有必要,它就会一直存在,在我的情况下,只要变量a

    在您的情况下,由于 arraymap::map 的返回值没有分配给变量,它们是临时值并且很快就会被删除。但是即使你将它分配给一个局部变量,你也不能返回对它的引用,因为当函数结束时局部变量会被删除。

    解决方案是返回一个拥有该值的迭代器。这样的工作:

    type IntegerCycle = Cycle<std::vec::IntoIter<i32>>;
    
    fn generate_cycles() -> [IntegerCycle; 2] {
      let cycles = [
        [1, 2],
        [2, 4],
      ];
      cycles
        .map(|points| {
          points.map(|point| point*2)
        })
        .map(|points| {
          points.to_vec().into_iter().cycle()
        })
    }
    

    不幸的是,您必须使用Vec 而不是数组,因为数组没有IntoIterator 实现(有切片,但它们不拥有值)。

    如果您想避免Vec 的额外分配,您可以使用arrayvec 板条箱,它允许将迭代器带到数组:

    type IntegerCycle = Cycle<arrayvec::IntoIter<[i32; 2]>>;
    
    fn generate_cycles() -> [IntegerCycle; 2] {
      let cycles = [
        [1, 2],
        [2, 4],
      ];
    
      cycles
        .map(|points| {
          points.map(|point| point*2)
        })
        .map(|points| {
            let a = arrayvec::ArrayVec::from(*points);
            a.into_iter().cycle()
        })
    }
    

    注意:似乎有人尝试将正确的IntoIterator impl for arrays by value 添加到std,但仍有一些待解决的问题。

    【讨论】:

      猜你喜欢
      • 2016-06-01
      • 1970-01-01
      • 2021-08-02
      • 1970-01-01
      • 2017-07-12
      • 2017-05-07
      • 2022-01-06
      • 2020-01-29
      • 2021-11-02
      相关资源
      最近更新 更多