【问题标题】:Lifetime of Option::map's argumentOption::map 参数的生命周期
【发布时间】:2014-09-26 09:23:34
【问题描述】:

我将一个字符串放入 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> 的类型(参见第二个代码块),但由于函数无法返回这种类型,因此这不是一个真正的选择。

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);
}

【问题讨论】:

    标签: rust


    【解决方案1】:

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

    最好的解决方案是直接在String 上进行就地修剪。遗憾的是,目前标准库中没有。

    您的第二种解决方案也可以稍作改动。而不是&amp;String,而是&amp;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);
    }
    

    【讨论】:

    • 感谢 PEPP 的回复。我实际上在使用 std::io 时遇到了问题。返回的类型是IoResult&lt;String&gt;(例如read_line)。因此不能使用第二种解决方案。因此,我必须使用 as_slice().trim().to_string() 解决方案或使用 try!宏并将其包装在一个额外的函数中。我说的对吗?
    【解决方案2】:

    如上所述,Option::map消耗原始值以产生输出值。这是最灵活和最有效的实现,因为您可以将 Option&lt;A&gt; 转换为 Option&lt;B&gt; 而无需克隆原始值。

    在这种情况下,解决方案是使用Option::as_ref 将您的Option&lt;String&gt;(实际上是&amp;Option&lt;String&gt;)转换为Option&lt;&amp;String&gt;。拥有Option&lt;&amp;String&gt; 后,您可以使用它而不会失去原始Option&lt;String&gt; 的所有权:

    fn main() {
        let s = Some("     i want to be trimmed    ".to_string());
    
        let x = s.as_ref().map(|z| z.trim());
    
        println!("{:?}", x);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-24
      • 1970-01-01
      • 2019-06-26
      • 2021-11-20
      • 1970-01-01
      • 2017-06-10
      • 2015-12-08
      相关资源
      最近更新 更多