2015-11-06 5 views
2

Я получаю ошибки типа при соединении разных типов итераторов.Цепочные итераторы разных типов

let s = Some(10); 
let v = (1..5).chain(s.iter()) 
     .collect::<Vec<_>>(); 

Выход:

<anon>:23:20: 23:35 error: type mismatch resolving `<core::option::Iter<'_, _> as core::iter::IntoIterator>::Item == _`: 
expected &-ptr, 
    found integral variable [E0271] 
<anon>:23  let v = (1..5).chain(s.iter()) 
          ^~~~~~~~~~~~~~~ 
<anon>:23:20: 23:35 help: see the detailed explanation for E0271 
<anon>:24:14: 24:33 error: no method named `collect` found for type `core::iter::Chain<core::ops::Range<_>, core::option::Iter<'_, _>>` in the current scope 
<anon>:24    .collect::<Vec<_>>(); 
         ^~~~~~~~~~~~~~~~~~~ 
<anon>:24:14: 24:33 note: the method `collect` exists but the following trait bounds were not satisfied: `core::iter::Chain<core::ops::Range<_>, core::option::Iter<'_, _>> : core::iter::Iterator` 
error: aborting due to 2 previous errors 

Но он отлично работает, когда проносясь:

let s = Some(10); 
let v = (1..5).zip(s.iter()) 
     .collect::<Vec<_>>(); 

Выход:

[(1, 10)] 

Почему Ржавчина способна выводить правильные типы для zip но не f или chain и как я могу это исправить? нотабене Я хочу, чтобы иметь возможность сделать это для любого итератора, поэтому я не хочу, чтобы решение, которое работает только для Range и Option.

ответ

10

Прежде всего, обратите внимание, что итераторы дают разные типы. Я добавил явные u8 номера, чтобы сделать типы более очевидными:

fn main() { 
    let s = Some(10u8); 
    let r = (1..5u8); 

    let() = s.iter().next(); // Option<&u8> 
    let() = r.next();  // Option<u8> 
} 

Когда вы chain два итераторы, оба итератора должен давать один и тот же тип. Это имеет смысл в качестве итератора не может «переключиться», какой тип он выдает, когда он доходит до конца одного и начинается на второй:

fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter> 
    where U: IntoIterator<Item=Self::Item> 
//      ^~~~~~~~~~~~~~~ This means the types must match 

Так почему же zip работы? Поскольку он не имеет такого ограничения:

fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter> 
    where U: IntoIterator 
//      ^~~~ Nothing here! 

Это потому, что zip возвращает кортеж с одним значением из каждого итератора; новый тип, отличный от типа исходного итератора. Один итератор может быть интегральным типом, а другой может вернуть свой собственный тип для всех zip забот.

Почему Ржавчина способна выводить правильные типы для zip но не для chain

Там нет типа умозаключения происходит здесь; это другое дело. Это просто несоответствие старого типа.

и как его исправить?

В этом случае, ваш внутренний итератор дает ссылку на целое число, Clone -able типа, так что вы можете использовать cloned, чтобы сделать новый итератор, клоны каждого значение, а затем оба итератора будут иметь тот же тип:

fn main() { 
    let s = Some(10); 
    let v: Vec<_> = (1..5).chain(s.iter().cloned()).collect(); 
} 

Если вы сделали с опцией, вы можете также использовать потребляющих итератор с into_iter:

fn main() { 
    let s = Some(10); 
    let v: Vec<_> = (1..5).chain(s.into_iter()).collect(); 
} 
+1

Спасибо за детали. Как вы думаете, каково влияние клонирования здесь? Мне интересно, стоит ли цепляться в таких случаях. –

+1

Влияние производительности, скорее всего, будет совершенно незначительным здесь.Клонирование целого числа является простой побитовой копией, и это то, что компьютеры делают^_ ^. Я добавил еще одно возможное решение. – Shepmaster

+1

Спасибо. Однако вопрос носит общий характер. Я не знаю, как клонирование работает в Rust; просто видя дополнительную стоимость в целом. Альтернатива с 'in_iter' выглядит хорошо - взглянув на реализацию. –

Смежные вопросы