我预计下面的两个函数是等价的。但是第一个没有编译。
pub fn does_not_work<I: IntoIterator>(values: I)
where
I::Item: AsRef<str>,
{
if let Some(value) = values.into_iter().nth(0).map(|item| item.as_ref()) {
if value == "first" {
println!("This should print");
}
}
}
pub fn does_work<I: IntoIterator>(values: I)
where
I::Item: AsRef<str>,
{
if let Some(value) = values.into_iter().nth(0) {
if value.as_ref() == "first" {
println!("This should print");
}
}
}
fn main() {
does_work(&["first"]);
}
编译错误是:
error[E0597]: `item` does not live long enough
--> src/main.rs:5:63
|
5 | if let Some(value) = values.into_iter().nth(0).map(|item| item.as_ref()) {
| ^^^^ - `item` dropped here while still borrowed
| |
| borrowed value does not live long enough
...
9 | }
| - borrowed value needs to live until here
代码被改变,以便比它来自的实际上下文更简洁,并且更清楚地说明了这一点。为了澄清我为什么要使用第一种方法,我在实际代码中多次使用value
,并且我不希望其中每一个都跟着.as_ref()
。
有没有办法让这项工作或Option::map
不是这种情况的好选择?还有另一种简洁的方法可以解决这个问题吗?
答案 0 :(得分:4)
创建新迭代器时,旧值不再可用。但是您需要存在旧值才能返回Some(value)
。在你的情况下,你将&[&'static str]
传递给函数,所以它保证足够长,但根据类型你也可以通过&[String]
。
在这种情况下,原始的String
可以被释放,并且你会留下一个悬空指针。如果不致电.as_ref()
,您可以保证原始值可以在Some(value)
中使用。
如果您只想跳过多个.as_ref()
来电,请改为:
pub fn does_work<I: IntoIterator>(values: I)
where
I::Item: AsRef<str>,
{
if let Some(value) = values.into_iter().next() {
let s = value.as_ref();
if s == "first" {
println!("This should print");
}
}
}
答案 1 :(得分:2)
因为map
取得参数item
的所有权,所以它会在返回后被销毁。这使得结果引用无效。
在使用Option::as_ref
之前,您应该应用Option<T>
将Option<&T>
转换为map
,如下所示:
pub fn does_not_work<I: IntoIterator>(values: I)
where
I::Item: AsRef<str>,
{
if let Some(value) = values.into_iter().next().as_ref().map(|item| item.as_ref()) {
if value == "first" {
println!("This should print");
}
}
}