为什么Rust中的函数调用在手动内联版本工作时无法编译?

mec1mxoz  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(84)

我有以下Rust MCVE:

#[derive(Clone)]
struct X {
    x: i32,
}
                 
fn fold1<I: Iterator, F>(mut it: I, f: F) -> I::Item
where
    I::Item: Clone,
    F: FnMut(I::Item, I::Item) -> I::Item, 
{
    let init = it.next().unwrap().clone();
    it.fold(init, f)
}

fn main() {
    let v = vec![X { x: 1 }, X { x: 2 }];

    // This does not compile:
    let s = fold1(v.iter(), |a, b| X { x: a.x + b.x }); 

    println!("{}", s.x);
}

字符串
这不会编译,并出现以下错误:

error[E0308]: mismatched types
  --> example.rs:19:36
   |
19 |     let s = fold1(v.iter(), |a, b| X { x: a.x + b.x });
   |                                    ^^^^^^^^^^^^^^^^^^ expected `&X`, found `X`
   |
help: consider borrowing here
   |
19 |     let s = fold1(v.iter(), |a, b| &X { x: a.x + b.x });
   |                                    +

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.


但是,如果我手动内联函数:

#[derive(Clone)]
struct X {
    x: i32,
}

fn main() {
    let v = vec![X { x: 1 }, X { x: 2 }];

    // The inlined version, however, does:
    let mut it = v.iter();
    let init = it.next().unwrap().clone();
    let s = it.fold(init, |a, b| X { x: a.x + b.x });

    println!("{}", s.x);
}


那么一切都很好。代码编译并做了预期的事情。
我真的看不出有什么不同。我做错什么了?
(And,作为后续,是否有可能编写一个类似fold1的函数,克隆迭代器的第一个元素,然后将其用作fold的初始元素?不,reduce不是答案。在迭代器上调用cloned()也不是答案。我真的只想克隆 * 第一个 *,而不是所有的。)

yzuktlbb

yzuktlbb1#

在你的工作代码中,你正在调用fold::<X, FnMut (X, &X) -> X>,但在非工作情况下,你试图调用fold::<&X, FnMut (&X, &X) -> &X>,因为I::Item&X。这不起作用,因为你的闭包的返回类型与初始值fold不一样。你需要修改fold1的声明,使其与工作代码匹配:

fn fold1<'a, T, I: Iterator<Item = &'a T>, F> (mut it: I, f: F) -> T
where
    T: Clone + 'a,
    F: FnMut (T, &'a T) -> T, 
{
    let init = it.next().unwrap().clone();
    it.fold (init, f)
}

字符串
Playground

相关问题