I am currently trying to implement a trait from a library (in my case serde
), which expects a trait to be returned (see example function next
), but i only have a supertrait available, but i do not know how to downcast a supertrait to a subtrait.
Example Code:
/// Imagine this type as a trait from a library, which i cannot change
trait SubTrait {
fn get_bool() -> bool;
}
trait SuperTrait: SubTrait {
fn get_string() -> String;
}
/// Imagine this type as a trait from a library, which i cannot change
trait GenericTrait {
fn next<T>(&mut self) -> Result<Option<T>, std::io::Error>
where
T: SubTrait;
}
struct SomeOtherStruct<'d, V: SuperTrait> {
field1: V,
_marker: std::marker::PhantomData<&'d ()>,
}
impl<'d, V> SomeOtherStruct<'d, V>
where
V: SuperTrait,
{
pub fn new(field: V) -> Self {
return Self {
field1: field,
_marker: std::marker::PhantomData,
};
}
pub fn do_something(self) -> Result<Option<V>, std::io::Error> {
return Ok(Some(self.field1));
}
}
struct ImplementingStruct<'d, V: SuperTrait> {
field1: V,
_marker: std::marker::PhantomData<&'d ()>,
}
/// Trying to implement the librarie's trait, while using a supertrait
impl<'d, V> GenericTrait for ImplementingStruct<'d, V>
where
// i have also already tried using "SuperTrait + SubTrait", but the same error happens
V: SuperTrait,
{
fn next<T>(&mut self) -> Result<Option<T>, std::io::Error>
where
T: SubTrait,
{
// Error: Expected "Option<T>" found "Option<V>"
return SomeOtherStruct::new(self.field1).do_something();
// TL;DR: how to cast "Option<V>" to "Option<T>"
}
}
rust version: 1.58.1
Notes:
SubTrait -> SuperTrait
, but this question is about SuperTrait -> SubTrait
)You cannot implement GenericTrait
this way.
trait GenericTrait {
fn next<T>(&mut self) -> Result<Option<T>, std::io::Error>
where
T: SubTrait;
}
This trait means: For any type T
the caller asks for, if T: SubTrait
, next
will return a T
(wrapped in Result<Option...>
). So, if the caller asks for String
, next
returns a String
; if the caller asks for i32
, next
returns an i32
; etc.
impl<'d, V> GenericTrait for ImplementingStruct<'d, V>
where
V: SuperTrait,
{
fn next<T>(&mut self) -> Result<Option<T>, std::io::Error>
where
T: SubTrait,
{
// Error: Expected "Option<T>" found "Option<V>"
return SomeOtherStruct::new(self.field1).do_something();
// TL;DR: how to cast "Option<V>" to "Option<T>"
}
}
This function body says: For any type T
the caller asks for, return V
instead. If the caller asks for String
, you would return V
. If the caller asks for i32
, you would still return V
.
You have broken your promise to the compiler: you said in the function signature you'd return a T
, but you're returning a V
instead. This isn't possible and has nothing to do with supertraits or subtraits. You can't write a function whose body and signature are in conflict.
In similar cases, sometimes it is appropriate to change the function signature. However, you can't change the function signature because that would make impl GenericTrait for ImplementingStruct
untrue. You can't implement a trait by not implementing the trait.
It is not clear what a solution might be in your case, but it is almost certainly unrelated to downcasting or supertraits. The same error happens with only one trait .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.