🫥

Iterator,Option,Resultのよく使いそうなメソッドと例(Rust)

2024/03/14に公開
2


頻繁に何だったっけ?となるのでリストや例を予め作っておくことにしました。思いのほか時間がかかったので記事にしました。備忘のため追加があれば更新する予定です。

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の消費がありません。(selfIter<&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を持つGood
Badなら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

白山風露白山風露

.copied().cloned()のみ元のIteratorの消費がありません。(selfIter<&T>)

元の Iterator は消費されますね。 Iterator の元のコンテナから impl Iterator<Item=&T> を作ってcopiedcloned を呼んだ場合、元のコンテナは消費されませんが。

scirexsscirexs

ご指摘ありがとうございます。
すぐにselfの表記を修正すべきかを確認できなかったため、とりあえず一文と関係部分を打ち消しました。また時間を取って認識の是正とともに表記を改めようと思います。