无法在特征对象上调用`fold`方法

时间:2018-02-16 18:41:40

标签: rust

我试图实现一个通用的缺点列表,比一本书第15章中使用的更为先进:

use std::fmt::Debug;

#[derive(Debug)]
enum List<T> {
    Nil,
    Cons(T, Box<List<T>>),
}

impl<T> List<T>
where
    T: Debug,
{
    fn from_iterable(iterator: &Iterator<Item = T>) -> Self {
        iterator.fold(List::Nil, |acc, value| List::Cons(value, Box::new(acc)))
    }
}

fn main() {
    println!("{:?}", List::from_iterable(&(1..10)));
}

playground

我的代码无法编译,它有一个非常令人困惑的消息:

error: the `fold` method cannot be invoked on a trait object
  --> src/main.rs:14:18
   |
14 |         iterator.fold(List::Nil, |acc, value| List::Cons(value, Box::new(acc)))
   |                  ^^^^

这条消息是什么意思?

我已经看到了这个与question有关的东西,但是即使这个是重复的,我目前的知识太有限了,无法连接点。

1 个答案:

答案 0 :(得分:4)

你有一个更大的问题。您已接受对不可变的特征对象的引用。这意味着您无法调用Iterator::next,这是迭代器上最原始的操作:

fn from_iterable(iterator: &Iterator<Item = T>) -> Self {
    iterator.next();
    panic!();
}
error[E0596]: cannot borrow immutable borrowed content `*iterator` as mutable
  --> src/main.rs:14:9
   |
13 |     fn from_iterable(iterator: &Iterator<Item = T>) -> Self {
   |                                ------------------- use `&mut Iterator<Item = T>` here to make mutable
14 |         iterator.next();
   |         ^^^^^^^^ cannot borrow as mutable

如果您按照此错误建议并更新调用网站以传递可变引用,则代码可以正常运行:

impl<T> List<T>
where
    T: Debug,
{
    fn from_iterable(iterator: &mut Iterator<Item = T>) -> Self {
        iterator.fold(List::Nil, |acc, value| List::Cons(value, Box::new(acc)))
    }
}

fn main() {
    println!("{:?}", List::from_iterable(&mut (1..10)));
}

但是,对于此类问题使用特征对象是,因为它们涉及动态调度和一些(小)运行时开销。相反,使用静态调度和泛型更为常见:

impl<T> List<T>
where
    T: Debug,
{
    fn from_iterable<I>(iterator: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        iterator
            .into_iter()
            .fold(List::Nil, |acc, value| List::Cons(value, Box::new(acc)))
    }
}

fn main() {
    println!("{:?}", List::from_iterable(1..10));
}

我也切换到IntoIterator,因为它对于来电者来说更符合人体工程学。

另见: