我正在尝试实现二叉树。我希望节点数据是分离的,因为有很多不同的方式可以实现它,而对树上的算法应该是通用的,与数据存储方式无关。
但是我遇到了借用检查器的奇怪问题。基本上,当我将 impl<TValue> Display for dyn Tree<TValue>
替换为 impl<TValue> Display for TreeNode<TValue>
时,问题就消失了。但我不知道为什么。Trait 是导致这个问题的原因吗?
我的代码如下:
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);
}
编译器会打印出:
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`
对我来说,这没有意义。函数体中没有捕获此值并试图在此函数范围之外保留它。这是借用检查器的限制吗?
dyn
,那么所有其他地方都需要dyn
,而且dyn
将无法使用,因为Tree
不是特质对象。这很奇怪。我相信 Rust 的编译器消息中仍然存在许多盲点。 - MaraTree
的类型实现Display
,但你无法使用静态分发来实现它,因为你不拥有Display
特质。请注意,动态方式只为dyn Tree
实现Display
,而不是所有实现Tree
的类型。 - Bamontan