Rust の Option 型について、Null 参照などの概念も踏まえて解説していきます。
他のプログラミング言語(C/C++、Python、Java、Ruby、Lisp など)を使ったことがある人は、null
やnil
に出会ったことがあるのではないでしょうか?null
やnil
の使用は、これらの言語が特定の変数に値がないことを示す方法です。
しかし、このため誤ってnull
を指す変数を使用してしまうと、簡単に(そして頻繁に)ミスを犯してしまいます。
ご想像のとおり、存在しない関数を呼び出したり、存在しない値にアクセスしようとすると、あらゆる種類のバグやクラッシュを引き起こす可能性があります。null
の生みの親は、これを「10 億ドルの間違い」とまで言っています。
このような問題を避けるため、Rust ではnull参照
を使用しません。しかし、特定の変数に値がないことを示す安全な方法がまだ必要です。そこで登場したのがOption型
です。Rust の変数には、値を持たない変数の代わりにOption列挙型
を使用することができます。
この列挙型には 2 つのバリエーションがあります。None
は Rust の null
に相当し、 Some(T) は T が任意の型の値であることを示しています。
enum Option<T> { None, Some(T), }
変数に None を設定するのだけです。
let nothing: Option<u32> = None; // 変数nothingにNoneを代入
しかし、Option型
に値を持たせたい場合、その値を直接代入することはできません。Option型
の変数と i32型
の変数とは等価ではありません。下記のようにSome
を使う必要があります。
let wrong_way: Option<i32> = -4; // エラー let right_way: Option<i32> = Some(-4); // 代入可 let another_right_way = Some(-4); // コンパイラがOption<i32>と推論する
よくあるエラーの例としてこちらも見てみましょう。
let number = 47; let option_number = Some(15); // i32型にOption<i32>型を足そうとしている(エラー) let compile_error = number + option_number;
Some に含まれる値を取得したい場合、まず、その値が存在するかどうかを確認する必要があります。
let mut some_words = Some("🦀"); match some_words { Some(str) => println!("カニさん{}", str), None => println!("何もありません。"), } // "カニさん🦀"と出力される。 some_words = None; // Noneを代入 // 上のmatch構文と全く同じ内容 match some_words { Some(str) => println!("カニさん{}", str), None => println!("何もありません。"), } // "何もありません。"と出力される。
さらに、Rust が null参照
の代わりにOption型
を使用する理由を説明します。ポイントは、Option 変数がSome
か、None
かをチェックしなければならないということです。
それ以外の場合、プログラムはコンパイルできません。コンパイラはあなたをnull
から守っているのです。