Почему `Option` поддерживает` IntoIterator`?
Я пытался выполнить итерацию по подразделу вектора строк, т.е. подклассу Vec<String>
. В течение каждой итерации я хотел передать строку как срез для функции.
Я не заметил, что Vec::get
возвращает Option
, и думал, что могу просто прямо перебрать возвращаемое значение:
fn take_str(s: &str) {
println!("{}", s);
}
fn main() {
let str_vec: Vec<String> =
["one", "two", "three", "uno", "dos", "tres"].iter().map(|&s|
s.into()).collect();
for s in str_vec.get(0..3) {
take_str(&s); // Type mismatch: found type `&&[std::string::String]`
}
}
Очевидно, я ожидал, что s
будет String
, но на самом деле &[String]
. Это связано с тем, что цикл for for фактически выполняет итерацию по Option
, возвращаемую Vec::get()
.
Я также написал следующий код, который показывает, что цикл for
фактически разворачивает Option
:
let foo = Option::Some ( ["foo".to_string()] );
for f in foo {
take_str(&f); // Same error as above, showing `f` is of type `&[String]`
}
Но это невероятно запутанно; Я никогда не ожидал (пока я не написал этот код и не понял, что он на самом деле делает), что Option
можно было бы развернуть, итерации по нему. Почему это поддерживается? Какой вариант использования для итерации по Option
?
Ответы
Ответ 1
Какой пример использования для итерации по Option
?
Моя любимая причина, одним словом, flat_map
:
fn main() {
let results = vec![Some(1), None, Some(3), None];
let sum: i32 = results.into_iter().flat_map(|x| x).sum();
println!("{}", sum)
}
Option
можно рассматривать как контейнер, который может содержать ровно нуль или один элемент. Сравните это с Vec
, который может содержать ноль или многие элементы. В большом наборе способов Option
представляет собой контейнер, похожий на Vec
!
Реализация IntoIterator
позволяет Option
участвовать в большей части API.
Обратите внимание, что IntoIterator
также реализуется для Result
по тем же причинам.
Но это невероятно запутанно
Да, это так, поэтому Clippy имеет для этого строку:
warning: for loop over `str_vec.get(0..3)`, which is an `Option`.
This is more readably written as an `if let` statement.
Это показывает, что существуют способы, которыми Option
не похож на контейнер для программиста.