I am trying to get a dynamically dispatchable borrow to an instance of an object implementing both Reader
and Seek
.
I understand that Rust can do dynamic dispatch as long as there is only one trait involved.
use std::io::{Read, Seek};
fn user(stream: &mut Read) {}
With two or more trait bounds though, I am forced to use a type parameter:
fn user_gen<T: Read + Seek>(stream: &mut T) {}
As the actual type underneath is a builder, it would have to store the borrowed object in some way, and using a type parameter for this would make the implementation more complex (I have three type parameters already).
Ideally, I would be able to do something like that:
fn user_dynamic(stream: &mut (Read + Seek)) {}
This does not compile:
error[E0225]: only auto traits can be used as additional traits in a trait object
--> src/main.rs:3:38
|
3 | fn user_dynamic(stream: &mut (Read + Seek)) {}
| ^^^^ non-auto additional trait
I understand that dynamic dispatch is done through fat pointers, and usually these only refer to one method table, not to multiple ones. I have not seen a statically compiled language that would support this, but such a feature would help me a lot.
We create a trait object by specifying some sort of pointer, such as a & reference or a Box<T> smart pointer, then the dyn keyword, and then specifying the relevant trait.
Traits can't have fields. If you want to provide access to a field from a trait, you need to define a method in that trait (like, say, get_blah ).
A trait is a language feature that tells the Rust compiler about functionality a type must provide. As you can see, the trait block looks very similar to the impl block, but we don't define a body, only a type signature. When we impl a trait, we use impl Trait for Item , rather than only impl Item .
A trait in Rust is a group of methods that are defined for a particular type. Traits are an abstract definition of shared behavior amongst different types. So, in a way, traits are to Rust what interfaces are to Java or abstract classes are to C++. A trait method is able to access other methods within that trait.
You can create an empty trait that merges those two traits:
use std::io::{Read, Seek};
trait SeekRead: Seek + Read {}
impl<T: Seek + Read> SeekRead for T {}
fn user_dynamic(stream: &mut SeekRead) {}
This will create a new vtable for SeekRead
that contains all the function pointers of both Seek
and Read
.
You will not be able to cast your &mut SeekRead
to either &mut Seek
or &mut Read
without some trickery (see Why doesn't Rust support trait object upcasting?)
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