First, I know I can use Box
if I want to define a recursive structure. For example,
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
}
}
But how can I make a trait on these structures via templates or trait object?
Due to the existence of fn append_next(...) -> Self
, I cannot create a trait object directly like this:
pub trait Linkable {
fn get_next(&self) -> Option<Box<dyn Linkable>>;
fn append_next(&mut self, next: impl Linkable) -> Self;
}
And we cannot return Option<Box<impl Linkable>>
or impl Linkable
for fn get_next(&self)
.
Then I tried the following implementation via generic templates and it does not work.
Because I need to assign the type of T
recursively when construct a new LinkNode
.
pub trait Linkable<T:Linkable<T> + Clone> : Clone {
fn get_next(&self) -> Option<Box<T>>;
fn append_next(&mut self, next: T) -> Self;
}
I finally implement it in this way, by creating other traits for assistance. And it works well. Again...Is there other better ways?
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()
}
}
BTW, I have some other questions during the exploration above: Why Rust forbids the impl Linkable
sugar, like the Box<impl Linkale>
? And why returning impl Linkable
is forbidden in a trait?
Updated after Ibraheem's answer:
Except the associated type implementation from Ibraheem, it is also fine to work like this. The core idea is to avoid the recursive type declaration in the 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,
}
This is mentioned in another question: Can I define a trait with a type parameter of itself in Rust?
question from:
https://stackoverflow.com/questions/65845197/how-to-define-a-recursive-trait-bound-in-rust