修改选择器时有没有办法在生锈中使用match()?

时间:2014-03-12 02:43:55

标签: rust

这个问题的命名很糟糕,但基本上,请考虑这个简单的例子:

您的表单中有一个链接列表:

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; {...}阻止你借用这个值?

1 个答案:

答案 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的工作方式。 (你没有显示它的代码所以我只能猜测它的作用。)

我做过的其他一些风格变化:

  • 四个空格,而不是两个;
  • 不要用下划线添加前缀(Rust有足够的隐私控制,不需要使用下划线);
  • if表达式周围没有括号(好了,现在已被match替换,所以没关系);
  • 如果匹配分支中只有一个语句,则不需要围绕它的大括号 - 只需在它之后使用逗号就可以了,
  • return x;只能在函数结尾时写成x