动态闭包 Vec 的错误类型推断

Bad type inference for the Vec of dynamic closures

我正在尝试获取部分应用函数的列表,如下所示:

fn partially_applied() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];

    xs.into_iter().map(|x| Box::new(move |y| x + y)).collect() 
}

编译器给我一个错误:

error[E0277]: 类型 std::vec::Vec u32>> 的值无法从类型元素的迭代器构建std::boxed::Box<[闭包@src/main.rs:4:41: 4:57]>


后续尝试也没有成功:

1.

fn partially_applied_with_explicit_collect_type() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];

    xs.into_iter().map(|x| Box::new(move |y| x + y)).collect::<Vec<Box<dyn Fn(u32) -> u32>>>() 
}
fn partially_applied_with_explicit_vec_type() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];

    let mut res: Vec<Box<dyn Fn(u32) -> u32>> = xs.into_iter().map(|x| Box::new(move |y| x + y)).collect(); 
    res 
}
fn partially_applied_with_explicit_push() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];

    let mut res = vec![];

    for x in xs { 
        res.push(Box::new(move |y| x + y)); 
    }

    res 
}

也只有这次尝试终于成功了!

fn partially_applied_with_explicit_push_and_vec_type() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];

    let mut res: Vec<Box<dyn Fn(u32) -> u32>> = vec![];

    for x in xs { 
        res.push(Box::new(move |y| x + y)); 
    }

    res 
}

为什么动态闭包的类型推断如此糟糕?

为什么 collect 在第一次尝试中没有奏效?

有没有更好的方法利用类型推断来表达这样的想法?

潜在的问题是每个闭包都有自己的不可命名类型,它是唯一的成员。此外,虽然编译器可以自动将特定的盒装闭包转换为 Box<dyn *closure's type*>,但它无法深入到泛型类型来执行向上转换。

所以下面是可以的:

fn closure() -> Box<dyn Fn(u32) -> u32> {
    Box::new(|x| x)
}

但这不是:

fn partially_applied() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];
    xs.into_iter().map(|x| Box::new(move |y| x + y)).collect() 
}

为什么不呢?

value of type `Vec<Box<dyn Fn(u32) -> u32>>` cannot be built from
`std::iter::Iterator<Item=Box<[closure@src/main.rs:12:37: 12:51]>>`

help: the trait `FromIterator<Box<[closure@src/main.rs:12:37: 12:51]>>`
is not implemented for `Vec<Box<dyn Fn(u32) -> u32>>`

因为 FromIteratorVec 的特征绑定是

impl<T> FromIterator<T> for Vec<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> { ... }
}

Box<[closure@src/main.rs]> 是不同于 Box<dyn Fn(u32) -> u32> 的类型。

所以问题不是“为什么 Rust 的类型推断在这里失败”,而是“为什么 Vec 没有实现以下内容”:

impl<T, U> FromIterator<T> for Vec<U>
where T: Into<U> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<U> { ... }
}

那个,我不知道。我怀疑当有多对 T,U 可以使事情正常时,这会导致类型推断本身的问题。

N.B。您可以将您的盒子转换为正确的类型,如下所示:

fn partially_applied() -> Vec<Box<dyn Fn(u32) -> u32>> {
    let xs = vec![1_u32, 2, 3];

    xs.into_iter()
        .map(|x| Box::new(move |y| x + y) as Box<dyn Fn(u32) -> u32>)
        .collect()
}