2015-09-16 7 views
6

リストを2つに分割する関数を構築したい:ある述語を満たす元のリストの要素を含むリストと、そうでないものをすべて含むリスト。以下は私の試みです:Fn型のサイズが実装されていない

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)); 
} 

しかし、私は2つのエラーを取得:

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 `[[email protected]/main.rs:17:39: 17:54]` 

を2番目のエラーは、閉鎖がFnではないことを暗示しているようです。私はどこかでオンラインで見つけた構文f: |&T| -> boolを使ってみましたが、それはRustの最新バージョンでは動作しないようです。

最初のエラーについては、私は、関数が既知のサイズを持っているが、どうやらそれはしないようにTSizedを作ることはそれを作るだろうと期待していました。

+3

将来の読者のために、このメソッドは既にイテレータに対して['partition'](http://doc.rust-lang.org/std/iter/trait.Iterator.html#method.partition)という名前で実装されています。 。 – Shepmaster

答えて

9

公式の錆書、特にthe chapter on closuresを読むべきです。関数の宣言が正しくありません。あなたはfに裸の形質型があることを指定していますが、これは不可能です。それはちょうど約Sizedのエラーについてです。代わりに、ジェネリック型パラメータを使用する必要があります。

fn split_filter<T: Clone, F>(a: &[T], f: F) -> (Vec<T>, Vec<T>) 
where 
    F: for<'a> Fn(&'a T) -> bool, 

私は&Vec<T>から&[T]aの種類をも変えてきました。前者を後者よりも好む状況はありません。必要に応じて&Vec<T>が自動的に&[T]に強制的に変換されます。 Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?

第2のエラーは、関数宣言の間違いと密接に関連しています。元の関数宣言では裸の特性型が指定されていますが、クロージャーはこの型を持たず、関数の特性を実装するだけです。

最終的なプログラムは次のようになります。

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)); 
} 

playground上でそれを試してみてください。

関連する問題