lsu*_*und 1 functional-programming lifetime rust borrowing
我想s通过迭代一个简单结构的向量来构建一个字符串,acc根据结构附加不同的字符串.
#[derive(Clone, Debug)]
struct Point(Option<i32>, Option<i32>);
impl Point {
fn get_first(&self) -> Option<i32> {
self.0
}
}
fn main() {
let mut vec = vec![Point(None, None); 10];
vec[5] = Point(Some(1), Some(1));
let s: String = vec.iter().fold(
String::new(),
|acc, &ref e| acc + match e.get_first() {
None => "",
Some(ref content) => &content.to_string()
}
);
println!("{}", s);
}
Run Code Online (Sandbox Code Playgroud)
运行此代码会导致以下错误:
error: borrowed value does not live long enough
Some(ref content) => &content.to_string()
^~~~~~~~~~~~~~~~~~~
note: reference must be valid for the expression at 21:22...
|acc, &ref e| acc + match e.get_first() {
^
note: ...but borrowed value is only valid for the expression at 23:33
Some(ref content) => &content.to_string()
^~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
问题是&str我创造的生命周期似乎立即结束.但是,如果to_string()首先返回a &str,则编译器不会抱怨.那么,有什么区别?
我怎样才能使编译器理解我希望字符串引用只要我构建就可以存活s?
您的分支结果之间存在差异:
"" 是类型的 &'static strcontent是类型的i32,所以你将它转换为a String然后从那个转换为&str...但是它&str与String返回的生命周期相同to_string,过早死亡正如@Dogbert所提到的,快速解决方法是acc +进入分支机构:
let s: String = vec.iter().fold(
String::new(),
|acc, &ref e| match e.get_first() {
None => acc,
Some(ref content) => acc + &content.to_string(),
}
);
Run Code Online (Sandbox Code Playgroud)
但是,它有点浪费,因为每次我们有一个整数,我们分配一个String(via to_string)只是为了立即丢弃它.
一个更好的解决方案是使用write!宏,它只是附加到原始字符串缓冲区.这意味着没有浪费的分配.
use std::fmt::Write;
let s = vec.iter().fold(
String::new(),
|mut acc, &ref e| {
if let Some(ref content) = e.get_first() {
write!(&mut acc, "{}", content).expect("Should have been able to format!");
}
acc
}
);
Run Code Online (Sandbox Code Playgroud)
它可能有点复杂,特别是因为格式化会增加错误处理,但由于它只使用单个缓冲区,因此效率更高.