我有一个字符串向量,我想从中提取一些数据并从中创建一个结构。它看起来像这样:
let mut my_struct = MyStruct::new(0, 0, 0);
let regex1 = Regex::new("...");
let regex2 = Regex::new("...");
for s_iter in my_str_vec.iter() {
if regex1.is_match(s_iter) {
// parsing the value
// .........
let var1 = regex1.captures("....");
// and assign it to to a field of the struct instance
my_struct.field1 = var1;
}
// do the same thing for other fields each step in the loop
// each step only one regex gets triggered
if regex2.is_match(s_iter) {
// parsing the value
// .........
let var2 = regex12.captures("....");
// and assign it to to a field of the struct instance
my_struct.field2 = var2;
}
}
// now "my_struct" is now completely initialized
如您所见,我必须使用mut
作为结构。没有mut
有没有办法做到这一点?我希望能够一次初始化结构,而不是mut
。或者我也可以在没有mut
的情况下考虑其他选项。
答案 0 :(得分:2)
在纯函数式语言中,您需要定义递归函数。在Rust中,它看起来像这样:
fn parse(my_str_vec: Vec<&str>) -> MyStruct {
let my_struct = MyStruct::new(0, 0, 0);
let regex1 = Regex::new(...);
let regex2 = Regex::new(...);
fn process_next<I>(regex1: Regex, regex2: Regex, mut str_iter: I, my_struct: MyStruct) -> MyStruct
where I: Iterator, I::Item: AsRef<str>
{
match str_iter.next() {
Some(s_iter) => {
let my_struct = if regex1.is_match(s_iter.as_ref()) {
let var1 = regex1.captures("var1");
MyStruct { field1: var1, ..my_struct }
} else if regex2.is_match(s_iter.as_ref()) {
let var2 = regex2.captures("var2");
MyStruct { field2: var2, ..my_struct }
} else {
my_struct
};
process_next(regex1, regex2, str_iter, my_struct)
}
None => my_struct
}
}
process_next(regex1, regex2, my_str_vec.iter(), my_struct)
}
请注意,此代码中仍有mut
:我们必须将str_iter
定义为可变,因为调用next()
需要接收器是可变的。
虽然内部函数是尾递归的,但Rust不保证尾调用,因此如果输入太大,它可能会因堆栈溢出而崩溃。就个人而言,我宁愿在这里使用mut
,就像在原始代码中一样,特别是因为Rust中的mut
意味着没有别名,这消除了一大类潜在的错误。