我将一个字符串放入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);
}
答案 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);
}