genericsrustdowncasttrait-objects

Problem with returning generic type from function


I have a function that searches through a list of trait objects and attempts to find one whose implementor is of a specific type, however the compiler doesent accept the return type.

pub struct GameObject{
    pub modules: Vec<Box<dyn ModuleTrait>>, 
}

impl GameObject {
   pub fn find_module_of_type<T: ModuleTrait>(&self) -> Result<T> {  
        //iterate through the modules
        self.modules
            .iter()
            .for_each(|m| {
                let module = m.as_any().downcast_ref::<T>();

                //see if mosule is of the correct type 
                if match module {
                    Some(T) => true,
                    None => false,
                } {
                    return Ok(module); //this is where the error happens
                }
            });
            
        Err(anyhow!("The specified module could not be found"))
    }
}

pub trait ModuleTrait {
    fn as_any(&self) -> &dyn Any;
}

pub struct Transform{
    pub value: i32
}

impl ModuleTrait for Transform {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

this gives the error

error[E0308]: mismatched types
  --> src\scene\game_object.rs:42:28
   |
42 |                     return Ok(module);
   |                            ^^^^^^^^^^ expected `()`, found `Result<Option<&T>, _>`
   |
   = note: expected unit type `()`
                   found enum `std::result::Result<Option<&T>, _>`
note: return type inferred to be `()` here
  --> src\scene\game_object.rs:42:28
   |
42 |                     return Ok(module);
   |                            ^^^^^^^^^^

For more information about this error, try `rustc --explain E0308`

The error message confuses me even more as it first tells me the unit return type is inferred but at the same time it isnt a unit type.

I tried to unwrap the module but that gave roughly the same error message


Solution

  • Finding an object already has a method on Iterator since you want to change the type as well I used find_map here instead:

    impl GameObject {
        pub fn find_module_of_type<T: ModuleTrait + 'static>(&self) -> Option<&T> {
            self.modules
                .iter()
                .find_map(|m| m.as_any().downcast_ref::<T>())  
        }
    }
    

    Modifications made: