2015-09-16 3 views
6

Ich möchte eine Funktion erstellen, die eine Liste in zwei teilt: eine Liste, die die Elemente der ursprünglichen Liste enthält, die ein bestimmtes Prädikat erfüllen, und eine andere, die alle enthält, die nicht . Unten ist mein Versuch:Sized ist nicht implementiert für den Typ 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)); 
} 

Allerdings habe ich zwei Fehler erhalten:

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]` 

Der zweite Fehler scheint, dass eine Schließung zu implizieren, ist kein Fn. Ich habe versucht, die Syntax f: |&T| -> bool zu verwenden, die ich irgendwo online gefunden habe, aber das scheint nicht in der neuesten Version von Rust zu funktionieren.

Was den ersten Fehler, ich hatte gehofft, dass TSized macht es machen würde, so dass die Funktion eine bekannte Größe hat, aber es hat offenbar nicht.

+3

Für zukünftige Leser ist diese Methode bereits für Iteratoren unter dem Namen ['partition'] implementiert (http://doc.rust-lang.org/std/iter/trait.Iterator.html#method.partition) . – Shepmaster

Antwort

9

Sie sollten das offizielle Rust-Buch lesen, insbesondere the chapter on closures. Ihre Funktionsdeklaration ist falsch. Sie geben an, dass f einen blanken Merkmals-Typ hat, was unmöglich ist; genau das ist der Fehler über Sized. Sie sollten stattdessen einen generischen Typ-Parameter verwenden:

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

Ich habe auch die Art der a von &Vec<T> zu &[T] geändert; Es gibt keine Situation, in der Sie ersteres dem letzteren vorziehen würden. &Vec<T> wird bei Bedarf automatisch auf &[T] gezwungen. Siehe Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?

Der zweite Fehler ist eng mit dem Fehler in der Funktionsdeklaration verbunden; Ihre ursprüngliche Funktionsdeklaration hat einen blanken Attributtyp angegeben, aber Schließungen haben diesen Typ nicht, sie implementieren nur das Funktionsmerkmal.

Das endgültige Programm sieht wie folgt aus:

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

Ausprobieren der playground.

Verwandte Themen