Option :: map的结果不够长

时间:2016-02-07 03:20:57

标签: rust lifetime

我预计下面的两个函数是等价的。但是第一个没有编译。

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不是这种情况的好选择?还有另一种简洁的方法可以解决这个问题吗?

2 个答案:

答案 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");
        }
    }
}