在地图闭包中生成新序列时出现奇怪的类型错误

时间:2016-10-11 01:44:22

标签: iterator rust tuples

我正在使用来自this question's answer的策略,我有兴趣生成另一个序列,它是由迭代器映射创建的两个函数的函数:

extern crate itertools_num;

use itertools_num::linspace;

fn main() {
    // 440Hz as wave frequency (middle A)
    let freq: f64 = 440.0;
    // Time vector sampled at 880 times/s (~Nyquist), over 1s
    let delta: f64 = 1.0 / freq / 2.0;
    let time_1s = linspace(0.0, 1.0, (freq / 2.0) as usize)
        .map(|sample| { sample * delta});


    let (sine_440,
         sine_100,
         summed_signal): (Vec<f64>, Vec<f64>, Vec<f64>) =
        time_1s.map(|time_sample| {
            let sample_440 = (freq * &time_sample).sin();
            let sample_100 = (100.0 * &time_sample).sin();
            let summed_sample = &sample_440 + &sample_100;

            (sample_440, sample_100, summed_sample)
        }).unzip();
}

与闭合指示一样,第三个信号是前两个信号的总和。我得到的错误令人困惑:

error[E0271]: type mismatch resolving `<[closure@src/main.rs:17:21: 23:10 freq:_] as std::ops::FnOnce<(f64,)>>::Output == (_, _)`
  --> src/main.rs:23:12
   |
23 |         }).unzip();
   |            ^^^^^ expected a tuple with 3 elements, found one with 2 elements
   |
   = note: expected type `(f64, f64, f64)`
   = note:    found type `(_, _)`
   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Map<std::iter::Map<itertools_num::Linspace<f64>, [closure@src/main.rs:11:14: 11:40 delta:_]>, [closure@src/main.rs:17:21: 23:10 freq:_]>`

error[E0308]: mismatched types
  --> src/main.rs:17:9
   |
17 |         time_1s.map(|time_sample| {
   |         ^ expected a tuple with 3 elements, found one with 2 elements
   |
   = note: expected type `(std::vec::Vec<f64>, std::vec::Vec<f64>, std::vec::Vec<f64>)`
   = note:    found type `(_, _)`

我可以理解类型错误,但为什么第三元组项会被完全忽略?

3 个答案:

答案 0 :(得分:5)

您可以根据standard unzip

创建自定义unzip3实施
trait IteratorUnzip3 {
    fn unzip3<A, B, C, FromA, FromB, FromC>(self) -> (FromA, FromB, FromC) where
        FromA: Default + Extend<A>,
        FromB: Default + Extend<B>,
        FromC: Default + Extend<C>,
        Self: Sized + Iterator<Item=(A, B, C)>,
    {
        let mut ts: FromA = Default::default();
        let mut us: FromB = Default::default();
        let mut vs: FromC = Default::default();

        for (t, u, v) in self {
            ts.extend(Some(t));
            us.extend(Some(u));
            vs.extend(Some(v));
        }

        (ts, us, vs)
    }
}

impl<A, B, C, T: Iterator<Item=(A, B, C)>> IteratorUnzip3 for T{}

fn main() { 
    let freq: f64 = 440.0; 

    let (sine_440, sine_100, summed_signal): (Vec<f64>, Vec<f64>, Vec<f64>) = 
        [1.0, 2.0, 3.0].iter().cloned()
            .map(|time_sample| { 
                let sample_440 = (freq * &time_sample).sin(); 
                let sample_100 = (100.0 * &time_sample).sin(); 
                let summed_sample = &sample_440 + &sample_100; 
                (sample_440, sample_100, summed_sample) 
            }).unzip3(); 

    println!("{:?}\n{:?}\n{:?}", sine_440, sine_100, summed_signal);
}

Playground

答案 1 :(得分:4)

Iterator::unzip仅支持2元组。您可以从Self: Iterator<Item=(A, B)>子句中出现的特征绑定where来判断这一点。

答案 2 :(得分:4)

Iterator::unzip仅定义为返回两个元组的元组:

fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB) 
    where FromA: Default + Extend<A>, 
          FromB: Default + Extend<B>,
          Self: Iterator<Item=(A, B)>,

注意返回类型是(FromA, FromB) - 具有两个值的元组。