I have the following problem (it is simplified a bit).
There is a trait which supplies a set of functions which do not use self:
pub trait ImageFormat {
fn write(data: Vec<[u8; 3]>, path: &str, ...) -> io::Result<()>;
...
}
with several implementations.
There also is a struct which uses functions from that trait:
pub struct Images<T: ImageFormat> {
path: String,
...
}
impl<T> Images<T> where T: ImageFormat {
pub fn setup(path: &str, ...) -> Images<T> {
Images {
path: String::from(path),
...
}
}
fn write(&mut self, data: Vec<[u8; 3]>, ...) -> io::Result<()> {
T::write(data, &self.path[..], ...)
}
...
}
This does not compile, because the struct does not have a field of type T. It works if I do this, but it feels like a hack:
pub struct Images<T: ImageFormat> {
_image_format: Option<T>,
path: String,
...
}
impl<T> Images<T> where T: ImageFormat {
pub fn setup(path: &str, ...) -> Images<T> {
Images {
_image_format: None,
path: String::from(path),
...
}
}
...
}
Is there any idiomatic way of doing this?
PhantomData can be used "to mark things that "act like" they own a T".
So, you could write:
pub struct Images<T: ImageFormat> {
path: String,
phantom: PhantomData<T>, // mark that Image "acts like" it owns a T
}
In initialization, you simply provide a PhantomData for the respective field:
Images {
path: ...
phantom: PhantomData,
}
As mentioned by others, you may be better off without the type parameter in the first place, but I have had cases where they seem perfectly reasonable to me (e.g. if T provides functions that do not take a self).
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