Rust Option入門者向けの補足追記

Option

https://doc.rust-lang.org/std/option/enum.Option.html の補足追記です。

この記事は MIT ライセンスです。

is_some

Someならtrue

let x: Option<u32> = Some(2);
assert_eq!(x.is_some(), true);
let x: Option<u32> = None;
assert_eq!(x.is_some(), false);

is_none

Noneならtrue

let x: Option<u32> = Some(2);
assert_eq!(x.is_none(), false);
let x: Option<u32> = None;
assert_eq!(x.is_none(), true);

as_ref

Option を Option<&T> に変換する。この手法によって、元の値には触れず、参照のみを受け取ります。
borrow は発生しません。

let num_as_str: Option<String> = Some("10".to_string());
// First, cast `Option<String>` to `Option<&String>` with `as_ref`,
// then consume *that* with `map`, leaving `num_as_str` on the stack.
let num_as_int: Option<usize> = num_as_str.as_ref().map(|n| n.len());
println!("still can print num_as_str: {:?}", num_as_str);

as_mut

Option を Option<&mut T> に変換

let mut x = Some(2);
match x.as_mut() { Some(v) => *v = 42, None => {},
}
assert_eq!(x, Some(42));

expect

オプションをアンラップし、Someの中身を返す。
unwrapと異なる点は、panicが発生した場合に、msgが流れる

let x = Some("value");
assert_eq!(x.expect("the world is ending"), "value");

unwrap

Some(v) から vを取り出す。
もとの変数からは移動されてしまうので注意。
Noneだった場合はpanicが発生する

let x: Option<&str> = None;
x.expect("the world is ending"); // panics with `the world is ending`

unwrap_or

アンラップ時に、Noneだった場合は、orで指定したものを返す。制約として同じ型のものでなければいけない。

assert_eq!(Some("car").unwrap_or("bike"), "car");
assert_eq!(None.unwrap_or("bike"), "bike");

unwrap_or_else

アンラップ時にNoneだった場合は、or_elseで指定したクロージャの結果を返す。

let k = 10;
assert_eq!(Some(4).unwrap_or_else(|| 2 * k), 4);
assert_eq!(None.unwrap_or_else(|| 2 * k), 20);

map

アンラップ時にSomeだった場合は、Some(v)のvをクロージャに渡し、結果をSome(s)として受け取る。Noneだった場合はそのままNoneになる。

map_or

アンラップ時にSomeだった場合は、Some(v)のvをクロージャに渡し、結果をsとして受け取る。Noneだった場合はデフォルト値が渡される。結果sとデフォルト値は同じ型。

let x = Some("foo");
assert_eq!(x.map_or(42, |v| v.len()), 3);
let x: Option<&str> = None;
assert_eq!(x.map_or(42, |v| v.len()), 42);

map_or_else

Someだった場合もNoneだった場合もクロージャに渡す。結果の型はそれぞれのクロージャで同じでなければいけない。

let k = 21;
let x = Some("foo");
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
let x: Option<&str> = None;
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);

ok_or

Option型をResult型に変換する。失敗だった場合の処理は新たに追加する。

let x = Some("foo");
assert_eq!(x.ok_or(0), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or(0), Err(0));

or_or_else

Option型をResult型に変換する。失敗だった場合の処理は、クロージャで計算する。

let x = Some("foo");
assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or_else(|| 0), Err(0));

iter

イテレータに変換する。next()すると結果が変える。
二回next()するとNoneになる。

let x = Some(4);
assert_eq!(x.iter().next(), Some(&4));
let x: Option<u32> = None;
assert_eq!(x.iter().next(), None);

iter_mut

iterと一緒だが、ミュータブル

let mut x = Some(4);
match x.iter_mut().next() { Some(v) => *v = 42, None => {},
}
assert_eq!(x, Some(42));
let mut x: Option<u32> = None;
assert_eq!(x.iter_mut().next(), None);

and

引数の条件もSomeでなければ、全体的にNoneになる。

let x = Some(2);
let y: Option<&str> = None;
assert_eq!(x.and(y), None);
let x: Option<u32> = None;
let y = Some("foo");
assert_eq!(x.and(y), None);
let x = Some(2);
let y = Some("foo");
assert_eq!(x.and(y), Some("foo"));
let x: Option<u32> = None;
let y: Option<&str> = None;
assert_eq!(x.and(y), None);

and_then

NoneのときはNoneを返すが、Someだった場合は、クロージャの計算結果を Some<U> として返す。

fn sq(x: u32) -> Option<u32> { Some(x * x) }
fn nope(_: u32) -> Option<u32> { None }
assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
assert_eq!(Some(2).and_then(sq).and_then(nope), None);
assert_eq!(Some(2).and_then(nope).and_then(sq), None);
assert_eq!(None.and_then(sq).and_then(sq), None);

or

どちらかに値が入っていれば、最初にHITした値が帰る

let x = Some(2);
let y = None;
assert_eq!(x.or(y), Some(2));
let x = None;
let y = Some(100);
assert_eq!(x.or(y), Some(100));
let x = Some(2);
let y = Some(100);
assert_eq!(x.or(y), Some(2));
let x: Option<u32> = None;
let y = None;
assert_eq!(x.or(y), None);

or_else

値が含まれていればSomeを返すが、含まれていない場合は、クロージャが呼ばれその結果を返す。クロージャの結果はSomeかNoneである。

fn nobody() -> Option<&'static str> { None }
fn vikings() -> Option<&'static str> { Some("vikings") }
assert_eq!(Some("barbarians").or_else(vikings), Some("barbarians"));
assert_eq!(None.or_else(vikings), Some("vikings"));
assert_eq!(None.or_else(nobody), None);

get_or_insert

Nonen場合は、vをオプションに挿入し、含まれている値への変更可能な参照を返す。

let mut x = None;
{ let y: &mut u32 = x.get_or_insert(5); assert_eq!(y, &5); *y = 7;
}
assert_eq!(x, Some(7));

get_or_insert_with

Noneの場合、クロージャによって計算された値をオプションに挿入し、含まれている値への変更可能な参照を返す。

let mut x = None;
{ let y: &mut u32 = x.get_or_insert_with(|| 5); assert_eq!(y, &5); *y = 7;
}
assert_eq!(x, Some(7));

take

オプションから値を取り除き、Noneをその場所に残す。

let mut x = Some(2);
x.take();
assert_eq!(x, None);
let mut x: Option<u32> = None;
x.take();
assert_eq!(x, None);