未对Fn

时间:2015-09-16 21:16:17

标签: rust

我想构建一个将列表拆分为两个的函数:一个列表包含原始列表中满足某个谓词的元素,另一个列表包含所有不满足某个谓词的元素。以下是我的尝试:

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

但是,我收到两个错误:

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

第二个错误似乎暗示闭包不是Fn。我尝试使用我在网上找到的语法f: |&T| -> bool,但这似乎不适用于最新版本的Rust。

至于第一个错误,我原本希望制作T Sized以使函数具有已知大小,但显然它不会。

1 个答案:

答案 0 :(得分:16)

你应该阅读正式的Rust书,特别是the chapter on closures。你的函数声明不正确;你指定/** * Sets the background for a view while preserving its current padding. If the background drawable * has its own padding, that padding will be added to the current padding. * * @param view View to receive the new background. * @param backgroundDrawable Drawable to set as new background. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @SuppressWarnings("deprecation") public static void setBackgroundAndKeepPadding(View view, Drawable backgroundDrawable) { Rect drawablePadding = new Rect(); backgroundDrawable.getPadding(drawablePadding); int top = view.getPaddingTop() + drawablePadding.top; int left = view.getPaddingLeft() + drawablePadding.left; int right = view.getPaddingRight() + drawablePadding.right; int bottom = view.getPaddingBottom() + drawablePadding.bottom; int sdk = android.os.Build.VERSION.SDK_INT; if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(backgroundDrawable); } else { view.setBackground(backgroundDrawable); } view.setPadding(left, top, right, bottom); } 有一个特殊的特征类型,这是不可能的;这正是f的错误所在。您应该使用泛型类型参数:

Sized

我还将fn split_filter<T: Clone, F>(a: &[T], f: F) -> (Vec<T>, Vec<T>) where F: for<'a> Fn(&'a T) -> bool, 的类型从a更改为&Vec<T>;没有哪种情况你更喜欢前者和后者。必要时,&[T]会自动强制转为&Vec<T>。见Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?

第二个错误与函数声明中的错误密切相关;你的原始函数声明指定了一个裸特征类型,但是闭包没有这种类型,它们只是实现了函数特性。

最终的计划如下:

&[T]

playground上尝试。