RustのOption
Rustには null がありません。値がないかもしれないときは、Option を使って型そのもので表します。最初は少し手間に感じるかもしれませんが、これによって、ほかの言語で数えきれないほどのクラッシュを引き起こしてきた「null参照」というバグを、まるごと防げるのです。
Optionの形
Section titled “Optionの形”Option は、2つのバリアントを持つ列挙型(enum)です。
enum Option<T> { Some(T), // 値がある None, // 値がない}実は、もう見たことがあるはずです。ベクタの .get() も、HashMapの .get() も Option を返します。
Optionを作る
Section titled “Optionを作る”fn main() { let has_value: Option<i32> = Some(5); let no_value: Option<i32> = None;
println!("{:?}", has_value); println!("{:?}", no_value);}実行結果:
Some(5)NonematchでOptionを扱う
Section titled “matchでOptionを扱う”値を取り出す安全な方法は match です。Rustは両方のケースを処理するよう強制するので、「値がない」ケースをうっかり忘れることがありません。
fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("年齢は{value}歳です"), None => println!("年齢が入力されていません"), }}fn find_user(id: u32) -> Option<&'static str> { if id == 1 { Some("Alice") } else { None }}
fn main() { match find_user(1) { Some(name) => println!("見つかりました: {name}"), None => println!("ユーザーが見つかりません"), }
match find_user(99) { Some(name) => println!("見つかりました: {name}"), None => println!("ユーザーが見つかりません"), }}実行結果:
見つかりました: Aliceユーザーが見つかりませんユーザーが見つからないときに null を返したり例外を投げたりする代わりに、関数の戻り値の型そのものが、呼び出す側全員に「何も見つからないかもしれません」と伝えています。そして、コンパイラはその可能性を無視させてくれません。
近道:unwrap_orとunwrap
Section titled “近道:unwrap_orとunwrap”簡単な場面では、毎回 match を書くのは大げさに感じるかもしれません。そんなときの近道がいくつかあります。
fn main() { let age: Option<i32> = None;
let value = age.unwrap_or(0); // 値がなければ0を使う println!("{value}");}.unwrap() というメソッドもあります。値を直接取り出せますが、None だった場合はパニック(プログラムが停止)します。
let age: Option<i32> = Some(30);let value = age.unwrap(); // ここではageがSomeなので問題なし1. 最初の偶数
Section titled “1. 最初の偶数”スライスの中で最初に見つかった偶数を返し、なければ None を返す fn first_even(numbers: &[i32]) -> Option<i32> を書いてください。[3, 7, 8, 10] の結果は match で、[1, 3, 5] の結果は .unwrap_or(0) で表示しましょう。ヒント:スライスをループして、n % 2 == 0 になった時点で return Some(n) します。ループを抜けたら None を返します。
解答を見る
fn first_even(numbers: &[i32]) -> Option<i32> { for &n in numbers { if n % 2 == 0 { return Some(n); } } None}
fn main() { match first_even(&[3, 7, 8, 10]) { Some(n) => println!("最初の偶数: {n}"), None => println!("偶数はありません"), }
let fallback = first_even(&[1, 3, 5]).unwrap_or(0); println!("代わりの値を使うと: {fallback}");}実行結果:
最初の偶数: 8代わりの値を使うと: 02. 設定を調べる
Section titled “2. 設定を調べる”"音量" が 80 に設定されているだけの、設定用の HashMap を作ってください。そのあと "音量" と "明るさ" の2つのキーをループして、値があればそれを、なければ「設定されていません」というメッセージを表示します。ヒント:HashMapの .get(key) は Option を返すので、そのまま match できます。
解答を見る
use std::collections::HashMap;
fn main() { let mut settings = HashMap::new(); settings.insert("音量", 80);
for key in ["音量", "明るさ"] { match settings.get(key) { Some(value) => println!("{key} = {value}"), None => println!("{key}は設定されていません"), } }}実行結果:
音量 = 80明るさは設定されていませんOption<T>は、あるかもしれないし、ないかもしれない値を表します。Rustにはnullがありません。Some(value)は値を持っていて、Noneは何もないことを意味します。matchは両方のケースを扱う安全な方法です。コンパイラがケースの書き忘れを許しません。.unwrap_or(default)は代わりの値を返します。.unwrap()は値がNoneだとパニックするので、使いすぎないようにしましょう。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. 値がないかもしれないとき、Rustはnullの代わりに何を使いますか?
2. None の値に対して .unwrap() を呼ぶとどうなりますか?
3. age が None のとき、age.unwrap_or(0) はどうなりますか?
4. match がOptionから値を取り出す安全な方法とされるのはなぜですか?
5. このページで紹介したもののうち、すでにOptionを返すメソッドはどれですか?
スコア: 0 / 5
さらに詳しく
Section titled “さらに詳しく”- Enumを定義する(Option enumとNull値に勝るその利点)— The Rust Programming Language 日本語版:Rust が
nullの代わりにOptionを使う理由を説明した公式の解説です。 std::option— 標準ライブラリのドキュメント(英語):Optionでできることの全体像です。map、and_then、is_someなどの便利なメソッドも紹介されています。- Option と unwrap — Rust By Example 日本語版:
matchやunwrap、そしてパニックが起きる場面を、短い実行できる例で見られます。 Option<T>— 標準ライブラリのドキュメント(英語):メソッドの完全な一覧です。どのメソッドにも、そのままコピーできる小さな例が付いています。