はじめに
最近気が付いて、ちょっと感心したイディオムなので紹介します。
Rustで Vec<Option<T>> のようなデータを扱う際、None を無視して数値が入っている要素だけで最大・最小を比較したい場合は、 flatten() を利用できます。
実装コード
fn main() {
let data = vec![Some(10), None, Some(42), None, Some(5)];
// flatten() で None を除外して値を取り出す
let max_val = data.iter().flatten().max();
let min_val = data.iter().flatten().min();
println!("最大値: {:?}", max_val); // Some(42)
println!("最小値: {:?}", min_val); // Some(5)
}
なぜ flatten() で解決するのか?
flatten は、端的に言うと「コレクションの中身を展開して、平坦化する」機能です。
実はRustの標準ライブラリでは、Option<T> に対して IntoIterator トレイトが実装されています。Rustの設計思想として、Option<T> は「最大1つの要素を持つコレクション」のように振る舞うことができるのです。
-
Some(v):要素が 1つ ある状態 -
None:要素が 0個 の状態
今回のケースでは、イテレータに対して flatten() を呼ぶと、各要素(Option)をさらにイテレータとして展開しようとします。
-
Some(v)の場合: 中身のvを取り出してメインのイテレータに流す -
Noneの場合: 要素が 0 個なので、何も流さない(=自動的にスキップされる)
結果として None が消え、純粋な数値だけの集まりになります。そのため、その後に .max() や .min() を繋げるだけで、意図した通りの比較ができるようになります。
考察・気づき
- 二次元配列を一次元にする際に利用することが多かったので、
flattenは配列専用の機能であるという思い込みがありました。 -
Optionに対してmapやfilterなどは利用していたものの、「要素数0か1のコレクションとして振る舞う」という性質を意識すると、活用の幅が広がると感じました。
環境情報
- rustc 1.89.0 (29483883e 2025-08-04)