函数参数的特征不匹配

时间:2018-01-12 01:18:08

标签: rust

我有一段Rust代码可以编译,而另一段代码则非常相似。

有效的那个:

pub fn do_something(_: Box<Iterator<Item = f64>>) {}

fn main() {
    let iter = Box::new(vec![1.0].into_iter());
    do_something(iter);
}

失败者:

pub fn do_something(_: Box<Box<Iterator<Item = f64>>>) {}

fn main() {
    let iter = Box::new(Box::new(vec![1.0].into_iter()));
    do_something(iter);
}

区别在于我有一个Box<Box<..>>而不是Box<..>

我收到以下错误:

error[E0308]: mismatched types
 --> src/main.rs:5:18
  |
5 |     do_something(iter);
  |                  ^^^^ expected trait std::iter::Iterator, found struct `std::vec::IntoIter`
  |
  = note: expected type `std::boxed::Box<std::boxed::Box<std::iter::Iterator<Item=f64> + 'static>>`
             found type `std::boxed::Box<std::boxed::Box<std::vec::IntoIter<{float}>>>`

我正在解释这个错误,说“IntoIter没有特征Iterator”..但确实如此。有什么问题?

2 个答案:

答案 0 :(得分:2)

老实说,我根本不是Rust的专家,但我的期望是你展示的这两个片段都没有编译。这是因为,正如您所指出的那样,Iterator是一种特质,而不是一种类型,基本上您希望do_something接收任何实现Iterator类型。也许存在一个快捷方式,使得编译器可以将签名转换为泛型,如果其中一个类型是一个特征,这可能是为什么有时可行的,但那时我也不够熟悉Rust语言规范。 / p>

不要让do_something采用类型为Iterator(?)的内容,而是使其成为T类型的通用,其中T是特征绑定的。

pub fn do_something<T>(_: Box<Box<T>>) 
    where T: Iterator<Item = f64> + Send {}

fn main() {
    let iter = Box::new(Box::new(vec![1.0].into_iter()));
    do_something(iter);
}

Playground

或者,您将do_something完全限制为std::vec::IntoIter,并仅采用该类型的参数。

pub fn do_something(_: Box<Box<std::vec::IntoIter<f64>>>) {}

fn main() {
    let iter = Box::new(Box::new(vec![1.0].into_iter()));
    do_something(iter);
}

Playground

答案 1 :(得分:2)

由于[{3}}中讨论的原因,您无法将Box<Box<I>>强制转换为Box<Box<Iterator<Item = f64>>>,但您可以强制执行内部Box

pub fn do_something(_: Box<Box<Iterator<Item = f64>>>) {}

fn main() {
    let iter = Box::new(Box::new(vec![1.0].into_iter()) as Box<Iterator<Item = f64>>);
    //                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    do_something(iter);
}

this question

这是有效的,因为演员表是Playground。通过编写as Box<Iterator<Item = f64>>,您可以向编译器暗示它应该尝试使左侧的表达式适合该类型,而不是推断Box<IntoIter<f64>>,因为一旦它被包裹起来&#34;外部&#34; Box,您无法再对其进行更改。

或者(但不太清楚),您可以通过明确参数化Box::new(...)来使Box成为强制性网站:

    let iter = Box::<Box<Iterator<Item = f64>>>::new(Box::new(vec![1.0].into_iter()));

有效地做同样的事情。