A Mech
carries a driver, which is a Named
entity. At run-time, an omitted Mech
constructor consults external source for the specific type of driver to use.
trait Named {
fn name(self) -> String;
}
struct Person {
first_name: String,
last_name: String
}
impl Named for Person {
fn name(self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
pub struct Mech<'a> {
driver: Box<Named + 'a>,
}
impl<'a> Mech<'a> {
pub fn driver_name(self) -> String {
self.driver.name()
}
}
Method driver_name
returns ownership to a String
, for it to be further used in chained calls (in actual code it's a Command
). It fails compilation with:
error[E0161]: cannot move a value of type Named + 'a: the size of Named + 'a cannot be statically determined
--> src/lib.rs:22:9
|
22 | self.driver.name()
| ^^^^^^^^^^^
Making the trait Sized
fails the object safety:
trait Named: Sized {
fn name(self) -> String;
}
↓
error[E0038]: the trait `Named` cannot be made into an object
--> src/lib.rs:17:5
|
17 | driver: Box<Named + 'a>,
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Named` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
Is there a way to make this pattern happen?
Is there anything fundamental that I seem to be missing?
In case this is impossible to achieve, what's a good way to work around it?
As the compiler hinted, the trait cannot be statically determined because you are dealing with dynamic dispatch. Ownership is still possible in this scenario using self: Box<Self>
.
trait Named {
fn name(self: Box<Self>) -> String;
}
struct Person {
first_name: String,
last_name: String,
}
impl Named for Person {
fn name(self: Box<Self>) -> String {
format!("{} {}", self.first_name, self.last_name)
}
}
pub struct Mech<'a> {
driver: Box<Named + 'a>,
}
impl<'a> Mech<'a> {
pub fn driver_name(self) -> String {
self.driver.name()
}
}
fn main() {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With