我正在为带有计数的标签向量编写合并函数,但我正在借用错误。
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
的类似错误。它通常显示问题位置和导致问题的上一步移动,但不在此处。
我已尝试了许多排列,并且通过以下更改我已经将其编译,但我对所有克隆和重新创建元组以及重新创建Option
s感到不满意
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)
上的匹配应移动值,以便强制每个路径设置v1
和v2
。仍然不如Haskell那么干净,但更接近。
答案 0 :(得分:0)
在v1
表达式中创建元组时,变量v2
和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())
}
}
}
};
}
}
删除了@mcarton
提到的不必要的clone