fold方法不能在特征对象上调用

Yur*_*nko 4 rust

我正在尝试实现一个通用的Cons列表,该列表比本书第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)));
}
Run Code Online (Sandbox Code Playgroud)

游乐场

我的代码无法编译,并且有一个令人困惑的消息:

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)));
}
Run Code Online (Sandbox Code Playgroud)

此消息是什么意思?

我已经看到了这个与某种方式相关的问题,但是即使这个问题是重复的,我目前的知识也太局限了,无法连接各个点。

She*_*ter 7

您有更大的问题。您已经接受了对不可变的特征对象的引用。这意味着您不能调用Iterator::next迭代器上最原始的操作:

impl<T> List<T>
where
    T: Debug,
{
    fn from_iterable(iterator: &dyn Iterator<Item = T>) -> Self {
        iterator.next();
        panic!();
    }
}
Run Code Online (Sandbox Code Playgroud)
impl<T> List<T>
where
    T: Debug,
{
    fn from_iterable(iterator: &dyn Iterator<Item = T>) -> Self {
        iterator.next();
        panic!();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您遵循此错误建议并更新呼叫站点以传递可变引用,则您的代码有效:

impl<T> List<T>
where
    T: Debug,
{
    fn from_iterable(iterator: &mut dyn 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)));
}
Run Code Online (Sandbox Code Playgroud)

然而,这不是常见的使用对象特点对这种类型的问题,因为它们涉及的动态调度和运行时开销的一些(小)量。取而代之的是,在泛型中使用静态分配更为常见:

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

fn main() {
    println!("{:?}", List::from_iterable(1..10));
}
Run Code Online (Sandbox Code Playgroud)

我还改用了IntoIterator它,因为它对呼叫者更符合人体工程学。

也可以看看: