我可以在这里摆脱“mut”吗?

时间:2016-06-03 03:12:29

标签: functional-programming rust

我有一个字符串向量,我想从中提取一些数据并从中创建一个结构。它看起来像这样:

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的情况下考虑其他选项。

1 个答案:

答案 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意味着没有别名,这消除了一大类潜在的错误。