【问题标题】:Borrow in filter closure does not live long enough借用过滤器关闭的寿命不够长
【发布时间】:2017-03-26 20:57:51
【问题描述】:

当我尝试编译这段代码时(playground):

fn main() {
    let iter = "abc123".chars().filter(&|&c: &char| c.is_digit(10));
    match iter.clone().take(3).count() {
        3 => println!("{}", iter.collect::<String>()),
        _ => {}
    }
}

我收到以下错误:

error: borrowed value does not live long enough
 --> test.rs:2:41
  |
2 |     let iter = "abc123".chars().filter(&|c: &char| c.is_digit(10));
  |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here
  |                                         |
  |                                         temporary value created here
...
7 | }
  | - temporary value needs to live until here
  |
  = note: consider using a `let` binding to increase its lifetime

我知道该错误有助于告诉我在上面的行中使用let f = &amp;|c: &amp;char| c.is_digit(10); (working code) 声明闭包,但为什么这是必要的呢?

我也不确定为什么闭包必须包含两个引用 - &amp;|c: &amp;char|"abc123".chars() 不是简单地创建一个字符的迭代器吗?

【问题讨论】:

标签: rust lifetime


【解决方案1】:

但为什么这是必要的呢?

我真的不知道如何比错误消息更好地解释它:

temporary value only lives until here
temporary value created here

您正在语句中创建一个临时值(闭包本身),然后引用它。当语句结束时,值被销毁——没有人拥有它!问题是代码试图将 reference 保留为现在已销毁的值。如果编译器允许这样做,那么当它使用该引用时,谁知道会访问哪些随机数据。

闭包必须包含两个引用

嗯,它没有filter(|c| c.is_digit(10)) 工作得很好;类型推断允许将c 自动键入为&amp;char&amp;c 仅模式匹配并自动取消引用该值。这是多余的,因为方法调用automatically dereference

更大的问题是代码试图克隆一个包含闭包的迭代器,这是你做不到的(1234(天哪,人们在询问之前拒绝搜索题))。您选择解决此问题的聪明方法是将 reference 克隆到闭包,这很好。

问题循环回到对语句末尾被破坏的东西的引用。


如果目标是忽略所有非数字,跳过前 3 位,然后收集其余数字,您可以使用Iterator::skip

let iter = "abc123".chars().filter(|c| c.is_digit(10));
let together: String = iter.skip(3).collect();
println!("{}", together);

如果目标是只取前 3 位当且仅当有 3 位数字时,那么我可能总是收集这些数字,并检查是否结束:

let mut iter = "abc123".chars().filter(|c| c.is_digit(10));
let together: String = iter.by_ref().take(3).collect();

if iter.next().is_none() {
    println!("{}", together);
}

这使用Iterator::by_refby_ref 不是消耗迭代器,而是创建一个对它的可变引用。对迭代器的可变引用实现了Iterator,因此调用takecollect 工作正常。但是,当这些都完成后,iter 仍然有效。

【讨论】:

  • 是的,对不起,发生的事情是我最初有类似this 的东西,但后来我用&amp;|c: &amp;char| 试图安抚编译器。这只是我试图获得 MCVE,我知道这不是最好的方法。不过这真的很有启发性!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-26
  • 1970-01-01
  • 2020-01-07
  • 2020-12-17
相关资源
最近更新 更多