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
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:
for_each
→ find_map
that's what you want to do after all.Result
→ Option
If your only error is "object matching criteria not found" that's exactly what Option
is for. If you want to disambiguate errors further up the call chain you can always turn that Option
into a Result
with Option::ok_or
there.Copy
or Clone
a T
you can't really return a value, only a reference so Option<T>
→ Option<&T>
T: 'static
since that's a requirement to be able to downcast
to it (See the bound on Any
).