我是Rust的新手,想知道是否有一种自然的方式来编写以下内容,同时仍然在元组上进行模式匹配。
我有key
,value
,left
和right
成员的树状结构。我想创建一个类似于
fn insert(&mut self, k: K, v: V) -> Option<V> {
match (k.cmp(self.k.borrow()), &mut self.left, &mut self.right) {
(Ordering::Less, &mut None, _) => { self.left = Some(Box::new(TreeNode::new(k, v))); None },
(Ordering::Less, &mut Some(ref mut left), _) => left.insert(k, v),
(Ordering::Greater, &mut None, _) => { self.right = Some(Box::new(TreeNode::new(k, v))); None },
(Ordering::Greater, &mut Some(ref mut right), _) => right.insert(k, v),
(Ordering::Equal, _, _) => { let mut temp = v; std::mem::swap(self.v.borrow_mut(), temp.borrow_mut()); Some(temp) },
}
}
我喜欢这清楚地涵盖所有情况和结果操作,但是这不能编译,因为self.left
和self.right
被匹配语句中使用的临时元组可变地借用,这意味着我无法修改匹配操作范围内的self.left
或self.right
。以下替代方案
fn insert(&mut self, k: K, v: V) -> Option<V> {
match k.cmp(self.k.borrow()) {
Ordering::Less => match self.left {
None => { self.left = Some(Box::new(TreeNode::new(k, v))); None },
Some(ref mut left) => left.insert(k, v),
},
Ordering::Greater => match self.right {
None => { self.right = Some(Box::new(TreeNode::new(k, v))); None },
Some(ref mut right) => right.insert(k, v),
},
Ordering::Equal => { let mut temp = v; std::mem::swap(self.v.borrow_mut(), temp.borrow_mut()); Some(temp) }
}
}
并且应该在逻辑上等同,但我觉得前者更清楚,更简洁地描述了问题。作为Rust的新手,我不确定是否有能力从元组中提取可变引用并将其从动作中的None
更改为Some
值,因此我想问我是否有是我忽略的任何替代品。
我已将working和non-working版本的短片段上传到了围栏。
答案 0 :(得分:6)
有一种获取可变引用的方法,因为可以使用@
模式(在Haskell中称为as-pattern)将标识符绑定到整个模式表示的值:
fn insert(&mut self, k: K, v: V) -> Option<V> {
match (k.cmp(self.k.borrow()), &mut self.left, &mut self.right) {
(Ordering::Less, left @ &mut None, _) => {
*left = Some(Box::new(TreeNode::new(k, v)));
None
}
// ...
这就像在匹配组中编写let left = &mut self.left;
一样,但它具有工作的有用优势。