1

Consider the following code for binary tree

#[derive(Debug)]
struct Binary_Tree_Node<T: PartialOrd + Clone> {
    left: Binary_Tree<T>,
    value: T,
    right: Binary_Tree<T>
}

#[derive(Debug)]
struct Binary_Tree<T: PartialOrd + Clone> {
    node: Option<Box<Binary_Tree_Node<T>>> 
}

impl <T: PartialOrd + Clone>Binary_Tree<T> {
    fn new(value_to_insert: T) -> Binary_Tree<T> {
        Binary_Tree{node: 
            Some(
                Box::new(
                    Binary_Tree_Node{
                        left: Binary_Tree{node: None}, 
                        value: value_to_insert, 
                        right: Binary_Tree{node: None}
                    }
                )
            )
        }
    }

    fn map<F, U>(&self, f: F) -> Option<U> 
    where F: FnOnce(&Binary_Tree_Node<T>) -> U {
        self.node.as_ref().map(|node| f(&**node))
        // equivalent 
        //self.node.as_ref().map(|node| f(node))
    }
}
let mut test1 = Binary_Tree::new(10);
println!("{:#?}", test1.map(|node| node.value < 2));

This line confuses me

self.node.as_ref().map(|node| f(node))

as I expect rust to throw compiler error

self.node is of type Option<Box<Binary_Tree_Node<T>>>

self.node.as_ref() is of type Option<&Box<Binary_Tree_Node<T>>>

node in self.node.as_ref().map(|node| f(node)) is of type &Box<Binary_Tree_Node<T>>

&Box<Binary_Tree_Node<T>> is not equivalent to the generic constraint &Binary_Tree_Node<T>

The question is why both self.node.as_ref().map(|node| f(&**node)) and self.node.as_ref().map(|node| f(node)) work?

Jal
  • 1,694
  • 13
  • 24
  • 1
    I think in the current form this question is not useful for others. Could you perhaps provide a [mcve] and remove the unneeded context? And edit the title to reflect the "unexpected" `&Box` -> `&T` conversion (because I can't see how this relates to "generic constraint")? – Stefan Nov 29 '17 at 09:18

1 Answers1

4

This is a "Deref coercion", see nomicon Coercions:

Coercion is allowed between the following types:

  • [...]
  • Deref coercion: Expression &x of type &T to &*x of type &U if T derefs to U (i.e. T: Deref<Target=U>)

Box<T> implements Deref<Target=T>, so &Box<T> coerces automatically to &T like you'd have written &*node.

(I'm not sure what the & in "Expression &x" part is for, because we don't have a & at coercion site and it still works - could be a typo or a bug)

Also works from &String to &str: Playground

fn foo<T>(_v: T) {}

fn main() {
    {
        let v: &Box<i32> = &Box::new(5i32);
        foo::<&i32>(v);
        foo::<&i32>(&*v);
    }

    {
        let v: &String = &String::from("abc");
        foo::<&str>(v);
        foo::<&str>(&*v);
    }
}
Stefan
  • 4,624
  • 1
  • 18
  • 37
  • @Kroltan As far as I can tell only references are coerced with Deref; maybe you're talking about ["The Dot Operator"](https://doc.rust-lang.org/nomicon/dot-operator.html) (also see https://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules/28552082#28552082)? – Stefan Nov 30 '17 at 14:31