为什么在尝试获取对盒装值的引用时会得到期望的类型`()`?

时间:2017-07-28 12:28:42

标签: rust borrow-checker

我有这个结构:

pub struct Node<T> {
    value: T,
    left: Option<Box<Node<T>>>,
    right: Option<Box<Node<T>>>,
}

impl<T> Node<T> {
    pub fn getLeft(&self) -> Option<&Self> {
        if self.left.is_some() {
            Some(&(*(self.left.unwrap())))
            // Some(self.left.unwrap()) <= same result
        }
        None
    }
}

fn main() {}

由于我收到此错误,似乎存在类型不匹配:

error[E0308]: mismatched types
  --> src/main.rs:10:13
   |
10 |             Some(&(*(self.left.unwrap())))
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::option::Option`
   |
   = note: expected type `()`
              found type `std::option::Option<&Node<T>>`

我是Rust的新手,并且不明白为什么期望的类型是(),而它应该是Option<&Self>,我怎么能返回对框内节点的引用(我怎么能搬出借来的自我)?

2 个答案:

答案 0 :(得分:3)

这里的问题不是借用检查员。如果您的if没有else,则必须返回单位( ())。您正尝试从函数返回一个值,这意味着您需要拥有else分支,或使用return。即:

impl<T> Node<T> {
    pub fn getLeft(&self) -> Option<&Self> {
        if self.left.is_some() {
            Some(&(*(self.left.unwrap())))
        } else {
            None
        }
    }
}

好的,现在借用检查器是个问题。这是因为您正在引用临时(self.left.unwrap()的结果)。您需要访问Option 的内容而不移动它。让我们这样做:

impl<T> Node<T> {
    pub fn getLeft(&self) -> Option<&Self> {
        if self.left.is_some() {
            Some(&(*(self.left.as_ref().unwrap())))
        } else {
            None
        }
    }
}

那更好,但它只是丑陋。有unwrap,加上多余的括号,名称是非惯用的,最后整个分支本身是不必要的。让我们解决所有这些问题:

impl<T> Node<T> {
    pub fn get_left(&self) -> Option<&Self> {
        self.left.as_ref().map(|l| &**l)
    }
}

或者,如果你想要一些更清晰的东西:

impl<T> Node<T> {
    pub fn get_left(&self) -> Option<&Self> {
        if let Some(left) = self.left.as_ref() {
            Some(&**left)
        } else {
            None
        }
    }
}

答案 1 :(得分:2)

您收到错误是因为if块是表达式;您需要使用else关注它,以便函数的输出正确(Option<&Self>)。

此外,您可以利用if let获取Option的内部值;然后很容易从Box

中获取引用
impl<T> Node<T> {
    pub fn getLeft(&self) -> Option<&Self> {
        if let Some(ref left) = self.left { // if let
            Some(&*left) // return a reference to the content of the Box (in an Option)
        } else {
            None // or return None if self.left is None
        }
    }
}

使用示例:

fn main() {
    let test0 = Node {
        value: 0,
        left: None,
        right: None
    };

    let test1 = Node {
        value: 0,
        left: Some(Box::new(test0)),
        right: None
    };

    println!("{:?}", test1.getLeft()); // Some(Node { value: 0, left: None, right: None })
}