首先,我知道如果我想定义一个递归结构,可以使用Box
。例如,
struct LinkNode {
next: Option<Box<LinkNode>>
}
impl LinkNode{
fn get_next(&self) -> Option<Box<LinkNode>>{
None
}
fn append_next(&mut self, next: LinkNode) -> Self{
self
}
}
但是,我该如何通过模板或特征对象在这些结构体上创建一个特征呢?
由于存在 fn append_next(...) -> Self
,我不能直接创建一个特征对象如下:
pub trait Linkable {
fn get_next(&self) -> Option<Box<dyn Linkable>>;
fn append_next(&mut self, next: impl Linkable) -> Self;
}
我们无法返回Option<Box<impl Linkable>>
或impl Linkable
来代替fn get_next(&self)
。
接下来,我尝试使用通用模板进行以下实现,但并未成功。
因为在构造新的LinkNode
时需要递归地分配T
类型。
pub trait Linkable<T:Linkable<T> + Clone> : Clone {
fn get_next(&self) -> Option<Box<T>>;
fn append_next(&mut self, next: T) -> Self;
}
我最终是通过创建其他辅助的特征来实现它的,这种方法效果很好。但是...是否还有其他更好的方法呢?
pub trait Linkable: LinkClone{
fn get_next(&self) -> Option<Box<dyn Linkable>>;
}
pub trait LinkAppend {
fn append_next(&mut self, next: Box<dyn Linkable>) -> Box<dyn Linkable>;
}
pub trait LinkClone{
fn clone_box(&self) -> Box<dyn Linkable>;
}
impl<T> LinkClonefor T
where
T: 'static + Linkable+ LinkAppend + Clone,
{
fn clone_box(&self) -> Box<dyn Linkable> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Linkable> {
fn clone(&self) -> Box<dyn Linkable> {
self.clone_box()
}
}
顺便提一下,我在上面的探索过程中还有其他问题:为什么Rust禁止像Box<impl Linkable>
这样的impl Linkable
语法糖?以及为什么在trait中返回impl Linkable
是被禁止的?
在Ibraheem回答后更新:
除了从Ibraheem那里得到的关联类型实现外,也可以按照以下方式工作。核心思想是避免在trait中进行递归类型声明。
pub trait Linkable {
fn get_next<T:Linkable>(&self) -> Next<T>;
fn append_next<T:Linkable>(&mut self, next: Next<T>) -> Self;
}
struct Next<T: Linkable> {
node: T,
}
这在另一个问题中有提到:在Rust中,我能否定义一个具有其自身类型参数的trait?。