闭包中的借用存活时间不够长

3

当我尝试编译这段代码(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>()),
        _ => {}
    }
}

I get the following error:

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 = &|c: &char| c.is_digit(10); (有效代码),但为什么这是必要的呢?
我也不确定为什么闭包需要包含两个引用- &|c: &char|。难道"abc123".chars()不只是创建了一个字符的迭代器吗?

@Shepmaster 我猜我之前尝试问的是如何克隆一个迭代器(在我被错误消息弄糊涂之前)。那么,例如,我该如何做到这一点(我知道这不是最好的方法)? - undefined
1个回答

5

但是为什么这很必要呢?

我不太知道该如何解释,不过错误信息已经说得很清楚了:

temporary value only lives until here
temporary value created here
你正在创建一个临时值(闭包本身)并在语句中引用它。当语句结束时,该值将被销毁 - 没有任何对象拥有它!问题是代码试图保留对已销毁值的引用。如果编译器允许这样做,那么当它尝试使用该引用时,谁知道会访问到什么随机数据。

闭包必须包含两个引用

嗯,并不是必须的。 filter(|c| c.is_digit(10)) 可以正常工作;类型推断允许自动将 c 类型化为 &char&c 只是模式匹配并自动取消引用该值。这是多余的,因为方法调用自动取消引用

更大的问题在于代码试图克隆一个包含闭包的迭代器,这是不可能的(1, 2, 3, 4(好吧,在提问前人们拒绝搜索))。你巧妙地选择了一种解决方法,即克隆对闭包的引用,这是可以的。
问题出现在将引用指向语句末尾被销毁的内容上。
如果目标是忽略所有非数字字符,跳过前三个数字并收集其余数字,则可以使用 Iterator::skip 方法:
let iter = "abc123".chars().filter(|c| c.is_digit(10));
let together: String = iter.skip(3).collect();
println!("{}", together);

如果目标是仅在存在三个数字的情况下仅获取前三位数字,则我可能会始终收集这些数字,并检查它是否为结束符。
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_ref。它不会消耗迭代器,而是创建了一个可变引用。可变引用同样实现了Iterator,因此调用takecollect也能正常工作。然而,在完成这些操作后,iter仍然有效。


哎呀,抱歉,事情是这样的,我最开始使用了类似于这个链接的东西,但后来为了让编译器满意,我使用了&|c: &char|这样的写法。这只是我在试图创建一个MCVE(最小完整可复现例子),我知道这并不是最好的方法。这真的很有启发! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接