2015-05-26 4 views
31

Я пытаюсь написать программу, которая включает в себя фильтрацию и складывание по массивам. Я использовал The Rust Programming Language, first edition в качестве ссылки, но я не понимаю, что происходит, когда я формирую итераторы по массивам. Вот пример:Как перебирать массив?

fn compiles() { 
    let range = (1..6); 
    let range_iter = range.into_iter(); 
    range_iter.filter(|&x| x == 2); 
} 

fn does_not_compile() { 
    let array = [1, 4, 3, 2, 2]; 
    let array_iter = array.into_iter(); 
    //13:34 error: the trait `core::cmp::PartialEq<_>` is not implemented for the type `&_` [E0277] 
    array_iter.filter(|&x| x == 2); 
} 

fn janky_workaround() { 
    let array = [1, 4, 3, 2, 2]; 
    let array_iter = array.into_iter(); 
    // Note the dereference in the lambda body 
    array_iter.filter(|&x| *x == 2); 
} 

(Rust playground)

В первой функции, я следую, что итератор в диапазоне не брать на себя ответственность, поэтому я должен взять в лямбда filter «s в &x, но Я не понимаю, почему второй пример с массивом ведет себя по-разному.

ответ

25

В таких случаях очень полезно заставить компилятор рассказать вам тип переменной. Давайте вызвать ошибку типа, назначая закрывающий аргумент несовместимым типа:

array_iter.filter(|x| { let() = x; true }); 

Это терпит неудачу с:

error[E0308]: mismatched types 
    --> src/main.rs:12:33 
    | 
12 |  array_iter.filter(|x| { let() = x; true }); 
    |         ^^ expected &&{integer}, found() 
    | 
    = note: expected type `&&{integer}` 
       found type `()` 

Теперь мы знаем, тип x является &&{integer} - ссылка на ссылку на некоторые вид целого. Затем мы можем сопоставить это:

fn hooray() { 
    let array = [1, 4, 3, 2, 2]; 
    let array_iter = array.into_iter(); 
    array_iter.filter(|&&x| x == 2); 
} 

Вопрос теперь становится «почему это ссылка на ссылку»? Короткий вариант заключается в том, что iterator of an array returns references (см. Раздел type Item = &'a T). Кроме того, Iterator::filter passes a reference для закрытия, чтобы предотвратить перемещение и впоследствии потерять не Copy.

+1

Спасибо! Я выбрал этот ответ, потому что он прошел через меня, как я мог использовать компилятор, чтобы понять это самостоятельно. Я также оценил ссылки, чтобы узнать больше. – WillEngler

19

Массивы типа [T; N] в ржавчине, для любого типа элементов T и постоянного номера N. Это массив фиксированного размера.

Rust не реализует итераторы по значению для массивов на данный момент. Из-за этого все массивы берутся за кусочки (тип [T]), и из этого доступны методы среза. Массивы также получают итератор среза, который называется std::slice::Iter<'a, T> и имеет элементы типа &'a T: он итерации по ссылке!

Вот почему into_iter() на Range<i32> производит итератор i32into_iter() и на [i32; 5] производит итератор &i32.

Если вам нужны итераторы значения для массивов, они были реализованы в более широкой экосистеме, см. (1) и (2).

0

Как Shepmaster и bluss сказал, вы можете проверить documentation for the array type, в котором упоминается:

Массивы размеров от 0 до 32 (включительно) выполнить следующие черты, если тип элемента позволяет ему:

  • IntoIterator (реализован для &[T; N] и &mut [T; N])

Как говорится, это только для ссылок и отражается в его Item типах: type Item = &'a T и type Item = &'a mut T.