这个问题的命名很糟糕,但基本上,请考虑这个简单的例子:
您的表单中有一个链接列表:
struct Node<T> {
_next: Option<~Node<T>>,
_data: Option<T>
}
一个“推”操作,为链添加元素:
/** Attach a node as the 'next' node in this chain */
fn push<'a>(&'a mut self, value: T) -> &'a mut ~Node<T> {
if (self._next.is_none()) {
self._push_node(~Node::new(value));
} else {
let tmp = self._next.take().unwrap();
let mut next = ~Node::new(value);
next._push_node(tmp);
self._push_node(next);
}
return self._next.as_mut().unwrap();
}
这样可行,但感觉它更像是一个match()表达而不是if语句,如:
/** Attach a node as the 'next' node in this chain */
fn push<'a>(&'a mut self, value: T) -> &'a mut ~Node<T> {
match self._next {
None => { self._push_node(~Node::new(value)); },
Some(ref v) => { <----------------------------- :(
let tmp = self._next.take().unwrap(); <------- ???
let mut next = ~Node::new(value);
next._push_node(tmp);
self._push_node(next);
}
}
return self._next.as_mut().unwrap();
}
但是,由于上述线路,这不起作用;实际上我们正在修改_next的值,这是不可能发生的,因为我们为match语句的Some()范围借用了self._next。
有更好的方法吗?
你能以某种方式将匹配语句纯粹声明为匹配,这样一旦你进入Some()=&gt; {...}阻止你不借用这个值?
答案 0 :(得分:5)
由于Some(ref v)
,您 借用了该值。然后你没有使用它,所以Some(_)
本来没问题。但实际上,你做想要获取价值。所以你真正想要的是将take()
转移到比赛之外。
这是最终结果:
pub struct Node<T> {
next: Option<~Node<T>>,
data: Option<T>
}
/** Attach a node as the 'next' node in this chain */
pub fn push<'a>(&'a mut self, value: T) -> &'a mut ~Node<T> {
match self.next.take() {
None => self.push_node(~Node::new(value)),
Some(v) => {
let mut next = ~Node::new(value);
next.push_node(v);
self.push_node(next);
}
}
match self.next {
Some(ref mut t) => t,
None => unreachable!(),
}
// Sure, you could replace those four lines with self.next.as_mut().unwrap(),
// but I have a slight leaning towards highlighting the unreachable nature of
// the None branch. It makes it more explicit.
// Others will doubtless disagree with me on that point.
}
您也可以选择Some(ref mut v)
并直接操纵&mut ~Node<T>
值,但这可能需要改变push_node
的工作方式。 (你没有显示它的代码所以我只能猜测它的作用。)
我做过的其他一些风格变化:
if
表达式周围没有括号(好了,现在已被match
替换,所以没关系); return x;
只能在函数结尾时写成x
。