Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Проход по for i in 0..vector.len() и 'index out of bounds'

#rust


Делаю задачу для тренировки, в последнем for выскакивает ошибка о выходе за границы
вектора :


  thread '
' panicked at 'index out of bounds: the len is 22 but the index is 22', ../src/libcollections/vec.rs:1106* Не могу понять, почему так происходит, в цикле for не проверяется результат len() при каждом новом проходе цикла? fn main(){ let e = 0.005; let n = 30; let mut vector: Vec; vector = Vec::new(); for i in 0..n { let result:f32 = 1./(i as f32 + 1.).powf(2.0); vector.push( result ); } for i in 0..vector.len(){ println!("len:{:?}", vector.len()); if vector[i] < e { println!("{:?}", vector[i]); vector.remove(i); } } } Я переделал под while и всё работает, но заводить счётчик до цикла как-то не красиво, да и i+=1; тоже, можно ли как-то это оформить посимпотичнее? Вот что получилось вместо последнего for let mut i=0; while( i < vector.len() ){ if vector[i] < e { println!("{:?}", vector[i]); vector.remove(i); } i+=1; }


Ответы

Ответ 1



В добавление советую внимательно прочитать документацию по Vec и Iterator. Практически всегда, когда хочется сделать for i in 0..vec.len() в расте нужно использовать итерирование по вектору напрямую или какой-то метод самого вектора или итератора от него. В частности в данном случае гораздо лучше использовать Vec::retain(), а для построения Iterator::collect() и Iterator::map(): let mut vector = (0..n).map(|i| 1./(i as f32 + 1.).powf(2.0)).collect::>(); vector.retain(|item| item >= e); Плюс ещё в том, что если использовать библиотечные методы и итераторы, то не будет сгенерирован код для проверки выхода индекса за границы массива (bounds check), как при использовании операции индексирования [].

Ответ 2



С помощью выражения 0..vector.len() вы получаете итератор, который возвращает числа от 0 до исходной длины вектора. Однако внутри цикла вы удаляете элементы, поэтому индекс выходит за границы. Это не сишный for, здесь итератор создаётся один раз в самом начале, и его верхяя граница не обновляется вместе с изменением размера вектора. Если вы хотите менять длину вектора во время итерирования по нему, вам нужно использовать while, потому что в этом случае верхяя граница будет проверяться каждый раз. К слову, при таком способе удаления инкрементировать переменную цикла следует, только если элемент не был удалён, иначе вы пропустите идущие подряд элементы, которые подлежат удалению.

Комментариев нет:

Отправить комментарий