从 Option<Rc<RefCell<T>>> 解开并访问 T

YLy*_*Lyu 12 smart-pointers dereference rust

我正在尝试用 Rust 解决一些 Leetcode 问题。然而,我在 LeetCode 的实现过程中遇到了一些困难TreeNode

use std::cell::RefCell;
use std::rc::Rc;

// TreeNode data structure
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我想做一个中序遍历,如何解开 的TreeNode对象Option<Rc<RefCell<TreeNode>>>,访问它.val .left .right并将它们作为输入传递到递归函数中?

我努力了:

pub struct Solution;

impl Solution {
    pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
        let mut ret: Vec<i32> = vec![];
        match root {
            Some(V) => Solution::helper(&Some(V), &mut ret),
            None => (),
        }

        ret
    }

    fn helper(node: &Option<Rc<RefCell<TreeNode>>>, ret: &mut Vec<i32>) {
        match node {
            None => return,
            Some(V) => {
                // go to the left branch
                Solution::helper(
                    (*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
                        .into_inner()
                        .left,
                    ret,
                );
                // push root value on the vector
                ret.push(Rc::try_unwrap(Rc::clone(V)).unwrap_err().into_inner().val);
                // go right branch
                Solution::helper(
                    (*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
                        .into_inner()
                        .right,
                    ret,
                );
            }
        }
    }
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

游乐场

编译器抱怨:

use std::cell::RefCell;
use std::rc::Rc;

// TreeNode data structure
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但如果我尝试这个建议,它也会抱怨:

pub struct Solution;

impl Solution {
    pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
        let mut ret: Vec<i32> = vec![];
        match root {
            Some(V) => Solution::helper(&Some(V), &mut ret),
            None => (),
        }

        ret
    }

    fn helper(node: &Option<Rc<RefCell<TreeNode>>>, ret: &mut Vec<i32>) {
        match node {
            None => return,
            Some(V) => {
                // go to the left branch
                Solution::helper(
                    (*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
                        .into_inner()
                        .left,
                    ret,
                );
                // push root value on the vector
                ret.push(Rc::try_unwrap(Rc::clone(V)).unwrap_err().into_inner().val);
                // go right branch
                Solution::helper(
                    (*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
                        .into_inner()
                        .right,
                    ret,
                );
            }
        }
    }
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 7

解开TOption<Rc<RefCell<T>>>

确实不想尝试通过//删除Option、 theRc或 the中的值。相反,对 进行模式匹配,然后调用来获取对 的引用。RefCellunwraptry_unwrapinto_innerOptionborrowRefCellT

此外:

  1. 当您只关心一只手臂时,请使用if let而不是声明。match
  2. 变量使用snake_case. V不是一个合适的名字。
  3. 此处无需使用结构体,也无需公开定义辅助函数。普通函数和嵌套函数更简单并且暴露的细节更少。
  4. 构造 时无需提供显式类型ret
pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
    fn helper(node: &Option<Rc<RefCell<TreeNode>>>, ret: &mut Vec<i32>) {
        if let Some(v) = node {
            let v = v.borrow();

            helper(&v.left, ret);
            ret.push(v.val);
            helper(&v.right, ret);
        }
    }

    let mut ret = vec![];

    if let Some(v) = root {
        helper(&Some(v), &mut ret);
    }

    ret
}
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我不喜欢被迫构建Some,因此我可能会重新组织代码,这也允许我将其作为方法粘贴在TreeNode

impl TreeNode {
    pub fn inorder_traversal(&self) -> Vec<i32> {
        fn helper(node: &TreeNode, ret: &mut Vec<i32>) {
            if let Some(ref left) = node.left {
                helper(&left.borrow(), ret);
            }

            ret.push(node.val);

            if let Some(ref right) = node.right {
                helper(&right.borrow(), ret);
            }
        }

        let mut ret = vec![];
        helper(self, &mut ret);
        ret
    }
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: