0

我正在为带有计数的标签向量编写合并函数,但出现借用错误。

fn merge(mut l1: Vec<(String, u32)>, mut l2: Vec<(String, u32)>) -> Vec<(String, u32)> {
    let mut d1 = l1.drain(..);
    let mut d2 = l2.drain(..);
    let mut result = Vec::new();
    let mut v1 = d1.next();
    let mut v2 = d2.next();
    loop {
        match (v1, v2) {
            (None, None) => return result,
            (None, Some(x)) => {
                result.push(x.clone());
                v2 = d2.next()
            }
            (Some(x), None) => {
                result.push(x.clone());
                v1 = d1.next()
            }
            (Some(p1), Some(p2)) => {
                let (ref s1, t1) = p1;
                let (ref s2, t2) = p2;
                if s1 == s2 {
                    result.push((s1.clone(), t1 + t2));
                    v1 = d1.next();
                    v2 = d2.next();
                } else if s1 < s2 {
                    result.push(p1.clone());
                    v1 = d1.next();
                } else {
                    result.push(p2.clone());
                    v2 = d2.next();
                }
            }
        }
    }
}

给出错误:

error: use of moved value: `v1` [E0382]
         match (v1,v2) {
                ^~
help: run `rustc --explain E0382` to see a detailed explanation
note: `v1` was previously moved here because it has type `core::option::Option<(collections::string::String, u32)>`, which is non-copyable

和类似的错误v2。它通常显示问题位置和导致问题的先前移动,但此处不显示。

我尝试了许多排列,并且通过以下更改我已经编译它,但我对所有的克隆和重新创建元组和重新创建Options 不满意。

match (v1, v2) {
    (None, None) => return result,
    (None, Some(x)) => {
        result.push(x.clone());
        v1 = None;
        v2 = d2.next();
    }
    (Some(x), None) => {
        result.push(x.clone());
        v1 = d1.next();
        v2 = None;
    }
    (Some(p1), Some(p2)) => {
        let (ref s1, t1) = p1;
        let (ref s2, t2) = p2;
        if s1 == s2 {
            result.push((s1.clone(), t1 + t2));
            v1 = d1.next();
            v2 = d2.next();
        } else if s1 < s2 {
            result.push(p1.clone());
            v1 = d1.next();
            v2 = Some((s2.clone(), t2));
        } else {
            result.push(p2.clone());
            v1 = Some((s1.clone(), t1));
            v2 = d2.next();
        }
    }
}

添加我真正想写的内容以供参考,以防有人正在为借阅检查器寻找挑战:

fn merge(mut l1: Vec<(String, u32)>, mut l2: Vec<(String, u32)>) -> Vec<(String, u32)> {
    let mut d1 = l1.drain(..);
    let mut d2 = l2.drain(..);
    let mut result = Vec::new();
    let mut v1 = d1.next();
    let mut v2 = d2.next();
    loop {
        match (v1, v2) {
            (None, None) => return result,
            (None, Some(p2)) => {
                result.push(p2);
                v1 = None;
                v2 = d2.next()
            }
            (Some(p1), None) => {
                result.push(p1);
                v1 = d1.next();
                v2 = None
            }
            (Some(p1 @ (s1, _)), o2 @ Some((s2, _))) if s1 < s2 => {
                result.push(p1);
                v1 = d1.next();
                v2 = o2
            }
            (o1 @ Some((s1, _)), Some(p2 @ (s2, _))) if s1 > s2 => {
                result.push(p2);
                v1 = o1;
                v2 = d2.next()
            }
            (Some((s1, t1)), Some((_, t2))) => {
                result.push((s1, t1 + t2));
                v1 = d1.next();
                v2 = d2.next()
            }
        }
    }
}

请注意,匹配(v1, v2)应移动值,以便强制每个路径设置v1v2。仍然不如 Haskell 干净,但更接近。

4

1 回答 1

1

在表达式中创建元组时变量v1v2移出。match你需要在里面修改这些变量match,所以不能借用。

Option<T>你可以使用方法take()

fn merge(mut l1: Vec<(String, u32)>, mut l2: Vec<(String, u32)>) -> Vec<(String, u32)> {
    let mut d1 = l1.drain(..);
    let mut d2 = l2.drain(..);
    let mut result = Vec::new();
    let mut v1 = d1.next();
    let mut v2 = d2.next();
    loop {
        match (v1.take(), v2.take()) {//Takes the value out of the option, leaving a None in its place.
            (None, None) => return result,
            (None, Some(x)) => {
                result.push(x);
                v2 = d2.next()
            }//v1 is None
            (Some(x), None) => {
                result.push(x);
                v1 = d1.next()
            }//v2 is None
            (Some(p1), Some(p2)) => {
                use std::cmp::Ordering::{Equal, Less, Greater};
                match p1.0.cmp(&p2.0) {
                    Equal => {
                        result.push((p1.0, p1.1 + p2.1));
                        v1 = d1.next();
                        v2 = d2.next();
                    }
                    Less => {
                        result.push(p1);
                        v1 = d1.next();
                        v2 = Some(p2);
                    }//restore v2
                    Greater => {
                        result.push(p2);
                        v1 = Some(p1); //restore v1
                        v2 = d2.next();
                    }
                };
            }
        };
    }
}

我已经更改了最后一个分支的代码以避免不必要的借用。


这种方法的缺点是您可能会忘记为变量分配新值。我建议从match表达式中返回值:

fn merge(mut l1: Vec<(String, u32)>, mut l2: Vec<(String, u32)>) -> Vec<(String, u32)> {
    let mut d1 = l1.drain(..);
    let mut d2 = l2.drain(..);
    let mut result = Vec::new();
    let mut v = (d1.next(), d2.next());
    loop {
        v = match (v.0.take(), v.1.take()) {
            (None, None) => return result,
            (None, Some(x)) => {
                result.push(x);
                (None, d2.next())
            }
            (Some(x), None) => {
                result.push(x);
                (d1.next(), None)
            }
            (Some(p1), Some(p2)) => {
                use std::cmp::Ordering::{Equal, Less, Greater};
                match p1.0.cmp(&p2.0) {
                    Equal => {
                        result.push((p1.0, p1.1 + p2.1));
                        (d1.next(), d2.next())
                    }
                    Less => {
                        result.push(p1);
                        (d1.next(), Some(p2))
                    }
                    Greater => {
                        result.push(p2);
                        (Some(p1), d2.next())
                    }
                }
            }
        };
    }
}

clone删除了@mcarton 提到的不必要的 s

于 2016-04-17T11:01:16.797 回答