I am trying to implement a binary tree. I want the node data to be separate, because there are many different ways in which this can be implemented, while algorithms on the tree should be generic and independent of how the data is stored.
But I am running into a weird issue with the borrow checker. Basically, when I switch impl<TValue> Display for dyn Tree<TValue>
with impl<TValue> Display for TreeNode<TValue>
, the problem goes away. But I have no idea why. Why is the Trait causing this issue?
My code is this:
use std::fmt::{Display, Formatter};
struct TreeNode<TValue> {
value: TValue,
left: Option<Box<TreeNode<TValue>>>,
right: Option<Box<TreeNode<TValue>>>,
}
trait Tree<TValue> {
fn value(&self) -> &TValue;
fn left(&self) -> Option<&dyn Tree<TValue>>;
fn right(&self) -> Option<&dyn Tree<TValue>>;
}
impl<TValue> Display for dyn Tree<TValue>
where
TValue: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("(")?;
Display::fmt(self.value(), f)?;
f.write_str(", ")?;
match self.left() {
Some(ref x) => x.fmt(f)?,
None => f.write_str("None")?,
}
f.write_str(", ")?;
match self.right().as_ref() {
Some(x) => x.fmt(f)?,
None => f.write_str("None")?,
}
f.write_str(")")
}
}
impl<TValue> Tree<TValue> for TreeNode<TValue>
where
TValue: Display,
{
fn value(&self) -> &TValue {
&self.value
}
fn left(&self) -> Option<&dyn Tree<TValue>> {
self.left.as_ref().map(|x| &**x as &dyn Tree<TValue>)
}
fn right(&self) -> Option<&dyn Tree<TValue>> {
self.right.as_ref().map(|x| &**x as &dyn Tree<TValue>)
}
}
fn main() {
let tree = Box::new(TreeNode {
value: 1,
left: Some(Box::new(TreeNode {
value: 2,
left: None,
right: None,
})),
right: Some(Box::new(TreeNode {
value: 3,
left: None,
right: None,
})),
}) as Box<dyn Tree<i32>>;
println!("{}", tree);
}
And the compiler prints:
error[E0521]: borrowed data escapes outside of associated function
--> src\main.rs:24:15
|
19 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
| -----
| |
| `self` declared here, outside of the associated function body
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
...
24 | match self.left() {
| ^^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
To me, this makes no sense. Nothing in the function body captures this value and tries to keep it beyond the scope of this function. Is this some borrow checker limitation?
dyn
? should a left branch of a tree be able to be a tree of another type ? – Kortneykorunafmt
onx
, not when you doself.left()
. – Kortneykorunadyn
in the Trait itself, then all other places will requiredyn
anddyn
won't be usable because thenTree
is not a trait object. It's weird. I believe there still are many blind spots in Rust's compiler messages. – VitovitoriaDisplay
for all types that implTree
, and you can't do it with static dispatch, because you don't own theDisplay
trait. note that the dyn way only implementsDisplay
fordyn Tree
, not all types that implementTree
. – Kortneykoruna