Option :: map的参数的生命周期

时间:2014-09-26 09:23:34

标签: rust

我将一个字符串放入Option并尝试在其上进行映射,例如修剪字符串:

fn main() {
    let s = "     i want to be trimmed    ".to_string();
    let s_opt = Some(s);

    let x = s_opt.map(|z| z.trim());
    //     let x = s_opt.map(|z| z.trim().to_string());

    println!("'{:?}'", x);
}

编译器显示生命周期错误

error[E0597]: `z` does not live long enough
 --> src/main.rs:5:27
  |
5 |     let x = s_opt.map(|z| z.trim());
  |                           ^      - `z` dropped here while still borrowed
  |                           |
  |                           borrowed value does not live long enough
...
9 | }
  | - borrowed value needs to live until here

这很清楚,因为z仅在闭包中定义,而参数是按值传递的。

由于原始变量s适用于整个块,编译器是否应该能够确定z实际上是s

我能让这个工作的唯一方法是添加to_string(参见注释行),然后我创建一个新的字符串对象。

我发现的另一个解决方案是使s_opt成为Option<&String>的类型(参见第二个代码块),但由于函数不能返回这种类型,因此这不是一个选项。 / p>

fn main() {
    let s = "     i want to be trimmed    ".to_string();
    let s_opt = Some(&s);

    let x = s_opt.map(|z| z.trim());
    println!("'{:?}'", x);
}

如果map的默认实现与此类似,是否有一些我忽视或不会更好的事情?

fn my_map<'r, F>(o: &'r Option<String>, f: F) -> Option<&'r str>
where
    F: Fn(&'r String) -> &'r str,
{
    match *o {
        None => None,
        Some(ref x) => Some(f(x)),
    }
}

fn main() {
    let s = "     i want to be trimmed    ".to_string();
    let s_opt = Some(s);

    let x = my_map(&s_opt, |x| x.trim());
    println!("'{:?}'", x);
}

2 个答案:

答案 0 :(得分:2)

map函数使用迭代值,因此在调用给定闭包后它们不再存在。您无法返回对它们的引用。

最佳解决方案是直接在String进行就地修剪。可悲的是,目前标准库中没有。

您的第二个解决方案也可以进行一些小改动。取代&String而不是&str

fn main() {
    let s = "text".to_string();
    let s_opt = Some(s.as_str());
    let x = s_opt.map(|z| z.trim());
    println!("{:?}", x);
}

答案 1 :(得分:2)

如上所述,Option::map 使用原始值来生成输出值。这是最灵活,最有效的实现,因为您可以将Option<A>转换为Option<B>,而无需克隆原始值。

在这种情况下,解决方案是使用Option::as_ref将您的Option<String>(真正的&Option<String>)转换为Option<&String>。获得Option<&String>后,您可以在不失去原始Option<String>的所有权的情况下使用它:

fn main() {
    let s = Some("     i want to be trimmed    ".to_string());

    let x = s.as_ref().map(|z| z.trim());

    println!("{:?}", x);
}