I want to take the behaviors of two traits and aggregate them together into some new thing which can be used to constrain other structures, enums, etc.
Here is an example: Combine the behavior of Any
with some other trait. The intended purpose is to combine the downcast
and is
behaviors of Any
with some other concept, in this case a function which returns the name of an object.
use std::any::Any;
trait Named {
fn get_name(&self) -> String;
}
// Combine the behaviors of `Any` with the trait `Named`
trait DynamicDispatchTrait : Any + Send + Sync + 'static + Named {
}
struct MyType {
my_name: String,
}
How can I mark the structure MyType
as "something which behaves as trait DynamicDispatchTrait
?
My first thought was that MyType
should implement this trait. That doesn't seem to work:
impl DynamicDispatchTrait for MyType {
fn get_name(&self) -> String {
return format!("my_name_is:{}", self.my_name);
}
}
Here's why:
method `get_name` is not a member of trait `DynamicDispatchTrait`
The ultimate objective is to be able to write a function like this:
fn dynamic_function(dynamic: Box<dyn DynamicDispatchTrait>) -> String {
if let Some(thing) = dynamic.downcast_ref::<MyType>() {
// ok
}
else {
println!("error!");
return String::from("error");
}
// ok ... operate dynamically
let s = dynamic.get_name();
return s;
}
Attempting to implement each trait independently reduces the number of compiler errors:
struct MyType {
my_name: String,
}
// Implement trait Named separately
impl Named for MyType {
fn get_name(&self) -> String {
return format!("my_name_is:{}", self.my_name);
}
}
// Implement trait DynamicDispatchTrait separately
impl DynamicDispatchTrait for MyType { }
// Any not implemented?
This doesn't quite solve all the issues. The compiler now says:
no method named `downcast_ref` found for struct
`Box<(dyn DynamicDispatchTrait + 'static)>` in the current scope
I would have thought that occurs because there is no impl Any for MyType
.
Attempting to add that doesn't quite work.
impl Any for MyType { }
conflicting implementations of trait `Any` for type `MyType`
...
note: conflicting implementation in crate `core`:
- impl<T> Any for T
where T: 'static, T: ?Sized;
Is there a solution to the problem I am attempting to solve?
Trait Aggregation / Requirements Example:
This looks to behave in a way which is analogous to inheritance.
The point here being that MyTraitCombo
, when used in the context of a "trait object" has a vtable which permits dispatch of both the functions from the two traits it "inherits" from. ("Inherits" = "satisfies the requirements" / "trait bounds" of.)
trait MyTrait1 {
fn my_function_1(&self) -> String {
String::from("function_1")
}
}
trait MyTrait2 {
fn my_function_2(&self) -> String {
String::from("function-2")
}
}
trait MyTraitCombo : MyTrait1 + MyTrait2 {
}
// note works without &
fn my_dynamic(argument: Box<&dyn MyTraitCombo>) -> String {
let s1 = argument.my_function_1();
let s2 = argument.my_function_2();
format!("{}-{}", s1, s2)
}
impl MyTraitCombo for i64 {
}
impl MyTrait1 for i64 { }
impl MyTrait2 for i64 { }
fn main() {
let arg = 0i64;
let s = my_dynamic(Box::new(&arg)); // note works without &
println!("{}", s);
}