Casting & self method provided for object definition

I have a trait in which I want to provide a method. This method should be implemented in terms of some assistants who do not have a business inside the line and are sufficiently nontrivial that dynamic polymorphism makes more sense than their general nature. So I have the code in the lines

fn use_trait(x: &Trait) { println!("object says {}", x.needed()); } trait Trait { fn needed(&self) -> &str; fn provided(&self) { use_trait(self); } } struct Struct(); impl Trait for Struct { fn needed(&self) -> &str { "Hello, world!" } } fn main() { Struct().provided(); } 

Which, however, does not compile , with an error:

 error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied --> <anon>:9:19 | 9 | use_trait(self); | ^^^^ the trait `std::marker::Sized` is not implemented for `Self` | = help: consider adding a `where Self: std::marker::Sized` bound = note: required for the cast to the object type `Trait` 

I understand why - it is not guaranteed that someone does not implement the attribute for a non-standard type (conversion from &T where T: Trait to &Trait requires T: Sized , but the declaration does not require this).

However, the advice will not do what I need. I can add

 fn needed(&self) -> &str where Self: Sized 

but then the needed() method will not be available on &Trait (because Trait : ?Sized ), which makes the thing useless, because the type (the actual one that does something useful) is always treated as Arc<Trait> . By adding

 trait Trait: Sized 

even worse, because it does not allow &Trait ( Trait , because the type is not supported, therefore the Trait type does not implement the Trait attribute).

Of course I can just do

 fn use_trait<T: Trait>(x: &T) 

but in real code there is a lot behind it, so I donโ€™t want monomorphization there, especially because the trait is always treated as an object-object.

Is it possible to tell Rust that all types that impl Trait should be sorted, and here is the definition of a method that should work for all of them?

+6
source share
2 answers

Extended version of @JoshuaEntrekin answer :

The as_trait helper function can be added to a helper trait that gets the full implementation for all Sized types trying to implement Trait . Then the Trait artist does not have to do anything special and the conversion works.

 fn use_trait(x: &Trait) { println!("object says {}", x.needed()); } trait Trait : AsTrait { fn needed(&self) -> &str; fn provided(&self) where Self : AsTrait { use_trait(self.as_trait()); } } trait AsTrait { fn as_trait(&self) -> &Trait; } impl<T : Trait + Sized> AsTrait for T { fn as_trait(&self) -> &Trait { self } } struct Struct(); impl Trait for Struct { fn needed(&self) -> &str { "Hello, world!" } } fn main() { Struct().provided(); } 

(on play ).

It would also be possible to simply put provided in an auxiliary attribute, but then it would have to dynamically send Self methods to other methods unnecessarily.


Update: in fact, the fact is that you can still override provided .

Now the above can be improved by making it general. There is std :: makrer :: Unsize that is unstable at the time of this writing. We can not do

 trait Trait : Unsize<Trait> 

because Rust does not allow CRTP , but fortunately itโ€™s enough to set a restriction on the method. So

 fn use_trait(x: &Trait) { println!("object says {}", x.needed()); } trait Trait { fn needed(&self) -> &str; fn provided(&self) where Self: AsObj<Trait> { use_trait(self.as_obj()); } } trait AsObj<Tr: ?Sized> { fn as_obj(&self) -> &Trait; } // For &'a Type for Sized Type impl<Type: Trait> AsObj<Trait> for Type { fn as_obj(&self) -> &Trait { self } } // For trait objects impl AsObj<Trait> for Trait { fn as_obj(&self) -> &Trait { self } } struct Struct(); impl Trait for Struct { fn needed(&self) -> &str { "Hello, world!" } fn provided(&self) { println!("Aber dieses Objekt sagt GrรผรŸ Gott, Welt!"); // pardon my German, it is rusty. } } fn main() { let s: &Trait = &Struct(); s.provided(); } 

(on play )

This finally makes it transparent to developers of other versions.

See also this user stream .

0
source

You need an additional function as_trait on Trait and its implementation:

 trait Trait { fn needed(&self) -> &str; fn provided(&self) { use_trait(self.as_trait()); } fn as_trait(&self) -> &Trait; } struct Struct(); impl Trait for Struct { fn needed(&self) -> &str { "Hello, world!" } fn as_trait(&self) -> &Trait { self as &Trait } } 

You can try it on the playground. ( object objects )

+2
source

Source: https://habr.com/ru/post/1014813/


All Articles