简体   繁体   中英

How to Downcast a Supertrait to a SubTrait in Rust

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:

  • i know This Rust Issue exists, but i dont think it is related (it is about SubTrait -> SuperTrait , but this question is about SuperTrait -> SubTrait )
  • from what i can tell, Boxing is not a option here

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 .

Similar Questions

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM