2016-11-12 61 views
2

当我尝试编译此代码(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 = &|c: &char| c.is_digit(10);working code)在上面的行中宣布关闭,但为什么这是必要的?

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

+0

相关:http://stackoverflow.com/q/31374051/155423;附近的副本:http://stackoverflow.com/q/28776630/155423,http://stackoverflow.com/q/23969191/155423,[工作代码](http://play.integer32.com/?gist=feb39ad6c2bd1641dcf463b65d560986&version =稳定); TL; DR:你可能想使用'by_ref'。 – Shepmaster

+0

@Shepmaster我想我想问的是如何克隆一个迭代器(在我被错误消息弄糊涂之前)。所以我怎么做[this](例如https://play.rust-lang.org/?gist=a8f4f33423f100f857ffe2ce4f0263a8&version=stable&backtrace=0)(我知道这不是最好的办法)。 – gib

回答

5

but why exactly is this necessary?

我真的不知道该如何解释它比错误消息要好得多:

temporary value only lives until here 
temporary value created here 

您正在创建一个临时值在一份声明中(盖子本身),然后取一个参考到它。当陈述结束时,价值被破坏 - 没有东西拥有它!问题是代码试图保持参考到现在被销毁的值。如果编译器允许这样做,那么当它使用该引用时,谁知道将访问哪些随机数据。

the closure has to contain two references

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

更大的问题是,代码试图克隆包含关闭,你不能做一个迭代器(1234(善良,人拒绝问一个问题之前,搜索))。您选择解决此问题的巧妙方法是将参考克隆到闭包,这很好。

问题循环回到引用声明末尾被销毁的内容。


如果目标是忽略所有的非数字字符,跳过第3位,然后收集的数字的休息,你可以使用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。代替消费迭代器,by_ref创建一个可变的引用。可变引用迭代器实现Iterator,所以调用takecollect工作正常。但是,当这些完成后,iter仍然有效。

+0

是的,对不起,发生了什么是我最初有[this](https://play.rust-lang.org/?gist=080f87f21823940bb52e92bc55a1299c&version=stable&backtrace=0)之类的东西,但后来我用'&| c :&char |'试图安抚编译器。这只是我想要找到一个MCVE,我知道这不是最好的方式。 虽然这真的很有启发! – gib