sunboy_zgz
sunboy_zgz

Reputation: 11

Rust why compiler infers a different type beyond our expection

I have such a piece of code:

struct Node {
    value: u32,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
}
fn traverse(last_nodes: &mut VecDeque<&Node>, result: &mut Vec<u32>) {
    if last_nodes.len() == 0 {
        return;
    }
    let mut childrens = VecDeque::new();
    while let Some(node) = last_nodes.pop_front() {
        result.push(node.value);
        if let Some(n) = &node.left {
            childrens.push_back(&*n);
        }
        if let Some(n) = &node.right {
            childrens.push_back(&*n);
        }
    }
    traverse(&mut childrens, result)
}

pay more attention to below code, I want childrens to be a VecDeque<&Node> type

let mut childrens = VecDeque::new();

however, it gets a result like VecDeque<&Box<Node>> because of below code and inference of compiler

childrens.push_back(&*n);

but if we correct the above code to be more definate, we can get our codes passing the compiler

let mut childrens:VecDeque<&Node> = VecDeque::new();

I don't know if it is the imperfection of compiler

Upvotes: 0

Views: 51

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 70900

The compiler is correct. The type of &node.left and &node.right is &Option<Box<Node>>. As such, matching it against Some(n) makes n has type &Box<Node>, by match ergonomics. So &*n is also &Box<Node>, and you're creating a VecDeque<&Box<Node>>.

However, &Box<Node> can be coerced to &Node via deref coercion. So, if the compiler knows the type of the VecDeque is VecDeque<&Node>, and so it expects push_back() to take &Node, it will coerce &Box<Node> to that and everything will work perfectly.

Upvotes: 4

Related Questions