Help with inferred return type

In the following code, I can not figure out why the compiler is inferring the return of the process in OuterResult as Option<Option<T>> instead of just Option<T>.

Essentially, I guess I'm confused why it inferred T = Option<T>

My (naive) thought was that the filter applied should handle the Option<T>s that will be returned from iterating over inner_results.

Any insight is appreciated!

trait Inner{
    type Output;
    fn get(&self) -> Self::Output;
}

struct InnerResult<I, F> {
    iter: I,
    op: F,
}

impl<I, F> Inner for InnerResult<I,F>
where
    I: Iterator,
    F: Fn(I::Item, I::Item) -> I::Item,
{
    type Output = Option<I::Item>;
    fn get(&self) -> Self::Output {
        self.iter.reduce(self.op)
    }
}


trait Outer{
    type Output;
    fn process(&self) -> Self::Output;
}

struct OuterResult<T,F>{
    inner_results: Vec<Box<dyn Inner<Output = Option<T>>>>,
    op: F,
}

impl<T,F> Outer for OuterResult<T, F>
where
    F: Fn(T,T) -> T
{
    type Output = Option<T>;
    fn process(&self) -> Self::Output {
        self.inner_results
            .iter()
            .map(|inner| inner.get())
            .filter(|e| e.is_some())
            .reduce(self.op)
    }
}

fn main() {
   let reduce_op = |x,y| x+y;
   let inner1 = InnerResult {
       iter: 0..5,
       op: reduce_op,
   };
   let inner2 = InnerResult {
       iter: 6..10,
       op: reduce_op,
   };
   let outer = OuterResult {
       inner_results: vec![Box::new(inner1),Box::new(inner2)],
       op: reduce_op
   };
   
   let sum = outer.process();
    
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: expected a `FnMut<(Option<T>, Option<T>)>` closure, found `F`
  --> src/main.rs:43:21
   |
43 |             .reduce(self.op)
   |              ------ ^^^^^^^ expected an `FnMut<(Option<T>, Option<T>)>` closure, found `F`
   |              |
   |              required by a bound introduced by this call
   |
   = note: expected a closure with arguments `(T, T)`
              found a closure with arguments `(Option<T>, Option<T>)`
note: required by a bound in `reduce`
  --> /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/iter/traits/iterator.rs:2513:5

error[E0308]: mismatched types
  --> src/main.rs:39:9
   |
33 |   impl<T,F> Outer for OuterResult<T, F>
   |        - this type parameter
...
38 |       fn process(&self) -> Self::Output {
   |                            ------------ expected `Option<T>` because of return type
39 | /         self.inner_results
40 | |             .iter()
41 | |             .map(|inner| inner.get())
42 | |             .filter(|e| e.is_some())
43 | |             .reduce(self.op)
   | |____________________________^ expected `Option<T>`, found `Option<Option<T>>`
   |
   = note: expected enum `Option<T>`
              found enum `Option<Option<T>>`

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 2 previous errors

That's because inner.get() returns a Option, which leads to type incompatible error.

The fix is filter_map. But the ownership problem is more interesting to solve. Rust Playground

Thanks, I'm a little embarrassed I didn't try filter_map first, as that is what I convinced myself I was actually doing, oops!

This example isn't exactly what I'm trying to accomplish but I'm sure your ownership changes will come in useful!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.