问题
I am trying to solve some Leetcode problems with Rust. However, I ran into some difficulties with LeetCode's TreeNode
implementation.
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,
}
}
}
If I want to do an inorder traversal, how to unwrap the TreeNode
's Option<Rc<RefCell<TreeNode>>>
object, access its .val
.left
.right
and pass them as inputs into a recursive function?
I have tried:
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() {}
(Playground)
The compiler complains:
error[E0308]: mismatched types
--> src/lib.rs:42:21
|
42 | / (*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
43 | | .into_inner()
44 | | .left,
| |_____________________________^ expected reference, found enum `std::option::Option`
|
= note: expected type `&std::option::Option<std::rc::Rc<std::cell::RefCell<TreeNode>>>`
found type `std::option::Option<std::rc::Rc<std::cell::RefCell<TreeNode>>>`
help: consider borrowing here
|
42 | &(*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
43 | .into_inner()
44 | .left,
|
But if I try the suggestion, it complains as well:
error[E0507]: cannot move out of an `Rc`
--> src/lib.rs:42:22
|
42 | &(*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of an `Rc`
error[E0507]: cannot move out of data in a `&` reference
--> src/lib.rs:42:22
|
42 | &(*Rc::try_unwrap(Rc::clone(V)).unwrap_err())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| cannot move out of data in a `&` reference
| cannot move
回答1:
Unwrap and access
T
from anOption<Rc<RefCell<T>>>
You really don't want to try to remove the value from the Option
, the Rc
or the RefCell
via unwrap
/ try_unwrap
/ into_inner
. Instead, pattern match on the Option
and then call borrow
on the RefCell
to get a reference to the T
.
Additionally:
- Use
if let
instead of amatch
statement when you only care about one arm. - Variables use
snake_case
.V
is not an appropriate name. - There's no need to use a struct here, or to define the helper function publicly. A plain function and a nested function are simpler and exposes less detail.
- There's no need to provide an explicit type when constructing
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
}
Personally, I'm not a fan of being forced to construct the Some
, so I'd probably reorganize the code, which also allows me to stick it as a method on 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
}
}
See also:
- Why does Arc::try_unwrap() cause a panic?
来源:https://stackoverflow.com/questions/54012660/unwrap-and-access-t-from-an-optionrcrefcellt