I want to build a function that splits a list into two: one list that contains the elements of the original list that satisfy a certain predicate, and another that contains all the ones which do not. Below is my attempt:
fn split_filter<T: Clone + Sized>(a: &Vec<T>, f: Fn(&T) -> bool) -> (Vec<T>, Vec<T>) {
let i: Vec<T> = vec![];
let e: Vec<T> = vec![];
for u in a.iter().cloned() {
if f(&u) {
i.push(u)
} else {
e.push(u)
}
}
return (i, e);
}
fn main() {
let v = vec![10, 40, 30, 20, 60, 50];
println!("{:?}", split_filter(&v, |&a| a % 3 == 0));
}
However, I get two errors:
error[E0277]: the trait bound `for<'r> std::ops::Fn(&'r T) -> bool + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:1:47
|
1 | fn split_filter<T: Clone + Sized>(a: &Vec<T>, f: Fn(&T) -> bool) -> (Vec<T>, Vec<T>) {
| ^ `for<'r> std::ops::Fn(&'r T) -> bool + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `for<'r> std::ops::Fn(&'r T) -> bool + 'static`
= note: all local variables must have a statically known size
error[E0308]: mismatched types
--> src/main.rs:17:39
|
17 | println!("{:?}", split_filter(&v, |&a| a % 3 == 0));
| ^^^^^^^^^^^^^^^ expected trait std::ops::Fn, found closure
|
= note: expected type `for<'r> std::ops::Fn(&'r {integer}) -> bool + 'static`
found type `[closure@src/main.rs:17:39: 17:54]`
The second error seems to imply that a closure is not a Fn
. I tried using the syntax f: |&T| -> bool
which I found online somewhere, but that does not seem to work in the latest version of Rust.
As for the first error, I had hoped that making T
Sized
would make it so that the function has a known size, but apparently it doesn't.
You should read the official Rust book, especially the chapter on closures. Your function declaration is incorrect; you are specifying that f
has a bare trait type, which is impossible; that's exactly what the error about Sized
is about. You should use a generic type parameter instead:
fn split_filter<T: Clone, F>(a: &[T], f: F) -> (Vec<T>, Vec<T>)
where
F: for<'a> Fn(&'a T) -> bool,
I have also changed the type of a
from &Vec<T>
to &[T]
; there is no situation in which you would prefer the former to the latter. &Vec<T>
is automatically coerced to &[T]
when necessary. See Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?
The second error is closely tied to the mistake in the function declaration; your original function declaration specified a bare trait type, but closures do not have this type, they just implement the function trait.
The final program looks like this:
fn split_filter<T: Clone, F>(a: &[T], f: F) -> (Vec<T>, Vec<T>)
where
F: Fn(&T) -> bool,
{
let mut i: Vec<T> = vec![];
let mut e: Vec<T> = vec![];
for u in a.iter().cloned() {
if f(&u) {
i.push(u);
} else {
e.push(u);
}
}
return (i, e);
}
fn main() {
let v = vec![10, 40, 30, 20, 60, 50];
println!("{:?}", split_filter(&v, |&a| a % 3 == 0));
}
Try it on the playground.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With