🫥
Iterator,Option,Resultのよく使いそうなメソッドと例(Rust)
頻繁に何だったっけ?となるのでリストや例を予め作っておくことにしました。思いのほか時間がかかったので記事にしました。備忘のため追加があれば更新する予定です。
Iterator
表記について
表記 | 意味 |
---|---|
Coll<T> |
T型のコレクション |
Iter<T> |
T型のIterator |
コレクションから取得するメソッド
メソッド | 戻り値 | メモ |
---|---|---|
Coll<T>.iter() |
Iter<&T> |
|
Coll<T>.iter_mut() |
Iter<&mut T> |
|
Coll<T>.into_iter() |
Iter<T> |
Coll<T> を消費する(各要素の所有権を移動) |
よく使いそうなメソッド
self
であるIter<T>
の表記は省略しています。
.copied()
と.cloned()
のみ元のIteratorの消費がありません。(self
がIter<&T>
)
[2024-03-29追記]
すみません、全然違いました。今のところ大体都度.iter()
等しており困らないので各メソッドのself
を正確に知りたい方はこちらを参照ください。
- Iteratorを返すメソッド
メソッドの簡単な例 | 戻り値 | メモ |
---|---|---|
.filter(|&x| x > 2) |
Iter<T> |
bool式結果がtrueとなる要素群を返す |
.map(|x| x * 2) |
Iter<U> |
式結果U の要素群を返す |
.enumerate() |
Iter<(usize,T)> |
(0_usize..).zip(Iter<T>) と同義 |
.zip(Coll<U>.into_iter()) |
Iter<(T,U)> |
Iter<T> とIter<U> を合わせる |
.filter_map(|x| hash_map.get(x)) |
Iter<U> |
Option式結果がSome(U) の要素群を返す |
.flat_map(|str| str.chars(x)) |
Iter<U> |
各要素でのIter<U> 式結果の結合を返す |
.inspect(|&x| println!("{}",x)) |
Iter<T> |
メソッドチェーンの間で標準出力可能 |
.copied() |
Iter<T> |
Copyでコピー作成 (無い場合はcloned() ) |
- Iteratorを返さないメソッド
メソッドの簡単な例 | 戻り値 | メモ |
---|---|---|
.collect() |
Coll<T> |
型情報必要時:collect::<Vec<_>>() 等と書く |
.fold(10,|acc,&x| acc - x) |
U |
初期値<U> に式結果を順に適用した結果を返す |
.next() |
Option<T> |
次の要素が無ければNone
|
.all(|x| x > 2) |
bool |
全要素でbool式がtrueの時true を返す (and) |
.any(|x| x > 2) |
bool |
ある要素でbool式がtrueの時true を返す (or) |
.find(|&x| x > 2) |
Option<T> |
bool式結果がtrueとなる最初の要素を返す |
.for_each(|x| {foo_func(x);}) |
() |
各要素で引数の処理を実行 |
もうちょっと例
fn main() {
use std::collections::HashMap;
let int_ary = [11, 22, 33, 44, 55];
let time_ary = ["2024-03-12T23:36:59Z", "2023-02-11T22:35:58Z", "2022-01-10T21:34:57Z"];
let map = HashMap::from([(1, "foo"),(2, "bar")]);
assert_eq!(time_ary.iter().flat_map(|&s| s.split(&['-',':','T'])).all(|s| s.parse::<i32>().is_ok()), false);
assert_eq!(int_ary.iter().filter(|&&x| x % 2 != 0).find(|&&x| x == 77), None);
assert_eq!(int_ary.iter().map(|&x| x + 1).inspect(|x| print!("{}", x)).fold(0, |acc, x| (acc / 2) + x), 90); //1223344556
time_ary.iter().filter_map(|&s| s.find('4')).zip(int_ary).enumerate().for_each(|x| println!("{:?}", x));
//(0, (3, 11))
//(1, (15, 22))
map.keys().filter_map(|k| map.get_key_value(k)).for_each(|(&x, &y)| println!("{}, {}", x, y));
//1, foo
//2, bar
}
Option,Result
表記について
表記 | Optionでの意味 | Resultでの意味 |
---|---|---|
Good | Some<T> |
Ok<T> |
Bad | None |
Err<E> |
O,R | Option<T> |
Result<T,E> |
R,O | Result<T,E> |
Option<T> |
O,R<U> | Option<U> |
Result<U,E> |
よく使いそうなメソッド
self
であるO,Rの表記は省略しています。
ResultのErr向けの同様メソッドは省略しています。(.unwrap_err
,.expect_err
,inspect_err
等)
Option (簡単な例) | Result (簡単な例) | 戻り値 | メモ |
---|---|---|---|
.is_some() |
.is_ok() |
bool |
Goodならtrue (値消費無し) |
.is_none() |
.is_err() |
bool |
Badならtrue (値消費無し) |
.is_some_and(|x| x>2) |
.is_ok_and(|x| x>2) |
bool |
Goodかつbool式がtrueならtrue
|
--- | .is_err_and(|x| x>2) |
bool |
Badかつbool式がtrueならtrue
|
.ok_or("error") |
.ok() |
R,O | 相互変換 (引数はE )Some<->Ok, None<->Err |
.ok_or_else(|| "error") |
--- | R,O |
.ok_or の遅延評価版引数に関数を使う |
.unwrap_or("error") |
(Optionと同様) | T |
Goodの値を取得 Badなら T 型引数を返す |
.unwrap_or_else(|| "error") |
(Optionと同様) | T |
.unwrap_or の遅延評価版引数に関数を使う |
.unwrap_or_default() |
(Optionと同様) | T |
Goodの値を取得 Badなら T のデフォルト値を返す |
.map(|x| x.len()) |
(Optionと同様) | O,R <U> |
Goodなら 引数の関数返り値 U を持つGoodBadならBad |
.map_or(7,|x| x.len()) |
(Optionと同様) | U |
Goodなら第2引数の関数返り値U Badなら第1引数 |
.inspect(|x| println!("{}",x)) |
(Optionと同様) | O,R | Goodの値を確認 (実質値消費無し) |
.unwrap() |
(Optionと同様) | T |
Goodの値を取得 Badならパニックを起こす |
.expect("error") |
(Optionと同様) | T |
Goodの値を取得 Badなら msg: &str でパニック |
コレクションの操作例
コレクションになっているOption,Resultは以下のような操作も可能です。
fn main() {
let all_some: [Option<i32>; 3] = [Some(1), Some(2), Some(3)];
let part_none: [Option<i32>; 3] = [None, Some(1), None];
let all_ok: [Result<i32, i32>; 4] = [Ok(1), Ok(2), Ok(3), Ok(4)];
let part_err: [Result<i32, i32>; 4] = [Ok(1), Err(-2), Ok(3), Err(-4)];
// 処理結果群が全て成功したかどうか判別できる
assert_eq!(all_some.iter().copied().collect::<Option<Vec<_>>>(), Some(vec![1, 2, 3]));
assert_eq!(part_none.iter().copied().collect::<Option<Vec<_>>>(), None);
assert_eq!(all_ok.iter().copied().collect::<Result<Vec<_>,_>>(), Ok(vec![1, 2, 3, 4]));
assert_eq!(part_err.iter().copied().collect::<Result<Vec<_>,_>>(), Err(-2));
// 処理結果群の成功だけを抽出できる
assert_eq!(all_some.iter().filter_map(|&x| x).collect::<Vec<_>>(), vec![1, 2, 3]); //flat_mapでも可
assert_eq!(part_none.iter().filter_map(|&x| x).collect::<Vec<_>>(), vec![1]); //flat_mapでも可
assert_eq!(all_ok.iter().flat_map(|&x| x).collect::<Vec<_>>(), vec![1, 2, 3, 4]); //filter_map(|&x| x.ok())でも可
assert_eq!(part_err.iter().flat_map(|&x| x).collect::<Vec<_>>(), vec![1, 3]); //filter_map(|&x| x.ok())でも可
}
Discussion
元の
Iterator
は消費されますね。Iterator
の元のコンテナからimpl Iterator<Item=&T>
を作ってcopied
やcloned
を呼んだ場合、元のコンテナは消費されませんが。ご指摘ありがとうございます。
すぐに
self
の表記を修正すべきかを確認できなかったため、とりあえず一文と関係部分を打ち消しました。また時間を取って認識の是正とともに表記を改めようと思います。