Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
780 views
in Technique[技术] by (71.8m points)

rust - Sized is not implemented for the type Fn

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...