Reputation: 8533
I have this small Rust function:
pub fn factor(input_array: &mut [i32]) {
let x = input_array
.iter()
.filter(|&x| x % 2 == 0);
x
}
When I run this via cargo run
I get this error:
Compiling gettingrusty v0.0.1 (file:///home/lowks/src/rust/gettingrusty)
src/functional.rs:22:9: 22:10 error: mismatched types:
expected `()`,
found `core::iter::Filter<core::slice::Iter<'_, i32>, [closure@src/functional.rs:21:21: 21:36]>`
(expected (),
found struct `core::iter::Filter`) [E0308]
src/functional.rs:22 x
^
src/functional.rs:22:9: 22:10 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
Could not compile `gettingrusty`.
I tried a few return types such as slice::Iter<i32>
and core::slice::Iter<i32>
but seems like all of them are wrong. What should be the return type of my function?
Upvotes: 0
Views: 647
Reputation: 13616
Your function returns a Filter
object, so its actual return type is Filter<_, _>
for some generic arguments. That’s fine, but chances are, you’ll want to hide all the implementation details from the type signature and just say that your function returns some iterator. Unfortunately, there is no (as of today) easy way to do this.
The pattern that seems to be rather common is to use a newtype wrapper. The problem with this is that writing the wrapper is a little bit more difficult than one might expect, e.g. one will have to deal with lifetimes explicitly.
Here is a complete example:
use std::iter::Filter;
use std::slice::Iter;
struct FactorResult<'a, T: 'a>(Filter<Iter<'a, T>, fn(&&T) -> bool>);
impl<'a, T> Iterator for FactorResult<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> { self.0.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
}
fn factor(input_array: &[i32]) -> FactorResult<i32> {
fn even(x : &&i32) -> bool { **x % 2 == 0 }
FactorResult(input_array.iter().filter(even))
}
fn main () {
for x in factor(&[1,2,3,4]) {
println!("{}", x);
}
}
factor
function returns a FactorResult
which is just a wrapper that hides the actual underlying type.FactorResult
is that it is an Iterator
. The implementation of the trait is trivial, but I had to spell it out.FactorResult<T>
, but the type of the closure is anonymous so there is no way to refer to it. One could use a closure but the whole thing would have to be boxed in this case.Upvotes: 2
Reputation: 59065
Under normal circumstances, you could just copy+paste the found
part of the error message. There are two problems with that in this particular case.
First, core
isn't directly accessible. Various items are exposed by the standard library libstd
, but are actually defined by libcore
. Basically, the standard library is the public interface you are meant to use to access these items, but the compiler doesn't know that. Typically, you work around this by just replacing core::*
with std::*
.
The second problem is that the type includes a closure, and closures cannot be named. The simplest solution is to just not use a closure at all; you aren't capturing anything, anyway.
Doing that and just fixing the compile errors as they come up leads to:
pub fn factor(input_array: &mut [i32])
-> std::iter::Filter<std::slice::Iter<i32>, fn(&&i32) -> bool> {
fn even(x: &&i32) -> bool { **x % 2 == 0 }
let x = input_array
.iter()
.filter(even as for<'r> fn(&'r &_) -> _);
x
}
Upvotes: 3