|
Option列挙型は、値が存在しない場合があることを表す列挙型。
Option列挙型はstd::preludeに含まれているので、useしなくても使える。
Optionインスタンスを作るには、値がある場合はSomeを使い、値が無い場合はNoneを使う。
// 値を保持 let opt = Some(123); println!("{:?} {}", opt, opt.is_some()); // →true // 値が無い let opt: Option<i32> = None; println!("{:?} {}", opt, opt.is_some()); // →false
RustのOptionは列挙型で実装されている。
JavaのOptionalはひとつのクラスのみで定義され、ScalaのOptionは抽象クラスでSomeとNoneはそれを継承した別々のクラスになっている。
各言語がそれぞれの機能を駆使して実装しているのが面白い。
※以下のコードは、元のソースから分かりやすいように切り出したり変更したりしたもの
項目 | Rust(option.rs) | Java相当 | Scala相当(Option.scala) |
---|---|---|---|
定義 |
pub enum Option<T> { None, Some(T), } |
public final class Optional<T> { private static final Optional<?> EMPTY = new Optional<>(null); public static<T> Optional<T> empty() { return (Optional<T>) EMPTY; } public static <T> Optional<T> of(T value) { return new Optional<>(Objects.requireNonNull(value)); } private final T value; private Optional(T value) { // コンストラクター this.value = value; } 〜 } |
sealed abstract class Option[+A] { 〜 } final case class Some[+A](value: A) extends Option[A] { 〜 } case object None extends Option[Nothing] { 〜 } |
Rustの列挙型は、列挙子ごとに値を保持したりしなかったり出来る。 Some(T)はタプル構造体のような定義方法で、 Noneは値を持たない定義方法。 |
JavaはOptinalクラスのみを定義し、SomeやNoneに当たるものを取得するメソッドがある。 Noneに当たるものの実体として定数EMPTYを用意している。 また、実際の値を保持するvalueというフィールドがある。(Noneのときはvalueはnull) |
Scalaでは親クラスであるOptionを定義し、SomeもNoneもOptionを継承した別のクラスになっている。 「 case class Some(value: A) 」ではvalueというフィールドを定義している。「 case object None 」のobjectは、親クラスを継承した新しいクラスを定義しつつ、シングルトンインスタンス(アプリケーション内でただ一つのインスタンス)を作る構文。 |
|
Someの生成 |
let s = Some(123); |
var s = Optional.of(123); |
val s = Some(123) |
Some列挙子に値を指定してインスタンスを作る。 値が参照でない場合、値の所有権を奪う。 |
Javaではofメソッドに値を渡してSome相当のインスタンスを作る。 | ScalaのSome(123) はSome.apply(123) というメソッド呼び出し。(Scalaではapplyというメソッド名のときは「 .apply 」を省略して呼び出すことが出来る。そして、case classではapplyというメソッドが自動的に生成される) |
|
Noneの取得 |
let s1: Option<i32> = None; let s2 = None as Option<i32>; |
Optional<Integer> s1 = Optional.empty(); var s2 = Optional.<Integer>empty(); |
val s1: Option[Int] = None val s2 = None: Option[Int] |
None列挙子を使用する。 | JavaではemptyメソッドでNone相当のインスタンスを取得する。 | ||
判定の定義 |
pub const fn is_some(&self) -> bool { matches!(*self, Some(_)) } pub const fn is_none(&self) -> bool { !self.is_some() } |
public boolean isPresent() { return this.value != null; } public boolean isEmpty() { return this.value == null; } |
final def isDefined: Boolean = !isEmpty final def isEmpty: Boolean = this eq None |
matches!はマクロで、is_someでは以下のように展開される。pub const fn is_some(&self) -> bool { match *self { Some(_) => true, _ => false } } |
Javaではvalueフィールドで実際の値を保持しており、None相当の場合はvalueはnull。 | ScalaではNoneインスタンスと等しいかどうかで判定している。 | |
値取得の定義 |
pub const fn unwrap(self) -> T { match self { Some(val) => val, None => unwrap_failed(), } } |
public T get() { if (this.value == null) { throw new NoSuchElementException("No value present"); } return this.value; } |
// class Some def get: A = value // object None def get: Nothing = throw new NoSuchElementException("None.get") |
unwrapの第1引数はselfである。(&が付いていない) つまり、保持している値が参照でない場合は、呼び出し元から所有権を奪っている。(unwarpを呼んだ後は、呼び出し元のOptionはそれ以降使用不可能になる) |
ScalaのSomeとNoneは別クラスなので、getメソッドはそれぞれのクラス専用の実装になっている。 |
Option<T>のメソッド(抜粋)。[2024-10-03]
メソッド | 説明 | 例 | |
---|---|---|---|
is_some(&self) ->
bool |
Someかどうか。 | let some = Some(123); |
|
is_some_and(self,
f: impl FnOnce(T) -> bool) -> bool |
Someのときはfを実行してその結果を返す。 Noneのときはfalseを返す。 |
let some = Some(123); |
|
is_none(&self) ->
bool |
Noneかどうか。 | let some = Some(123); |
|
is_none_or(self,
f: impl FnOnce(T) -> bool) -> bool |
|||
unwrap系 |
Tが可変参照(&mut)のときは
、unrwapして関数から返すことは出来ない。(コンパイルエラーになる) →フィールドに保持したOption<可変参照>を取得する例 |
||
unwrap(self) -> T |
Someのときは値(と所有権)を返す。 Noneのときはパニックを起こす。 →?演算子 |
let opt = Some(123); |
|
expect(self, msg:
&str) -> T |
Someのときは値(と所有権)を返す。 Noneのときはメッセージ付きのパニックを起こす。 |
let opt = Some(123); |
|
unwrap_or(self,
default: T) -> T |
Someのときは値(と所有権)を返す。 Noneのときは引数defaultの値を返す。 |
let some = Some(123); |
|
unwrap_or_default(self)
-> T |
Someのときは値(と所有権)を返す。 NoneのときはTのデフォルト値を返す。 TがDefaultトレイトを実装しているとき(デフォルト値を返せるとき)だけ使用可能。 |
let some = Some(123); |
|
unwrap_or_else<F>(self,
f: F) -> T |
|||
unwrap_unchecked(self)
-> T |
|||
as_ref(&self) ->
Option<&T> |
Option<T>に対してOption<&T>を返す。 構造体のフィールドがOption<T>のとき、ゲッターメソッドでOption<&T>を返す際に便利。[2025-08-21] |
struct MyStruct { |
|
as_mut(&mut self) ->
Option<&mut T> |
Option<T>に対してOption<&mut T>を返す。 | let mut some = Some(123); |
|
as_pin_ref(self:
Pin<&Self>) -> Option<Pin<&T>> |
|||
as_pin_mut(self:
Pin<&mut Self>) -> Option<Pin<&mut T>> |
|||
as_deref(&self) ->
Option<&T::Target> |
Option<Derefを実装したT>に対してOption<Tの中身の不変参照>を返す。[/2025-08-22] →as_derefの使用例 |
let o: Option<String> = Some("abc".to_string()); |
|
as_deref_mut(&mut
self) -> Option<&mut T::Target> |
Option<DerefMutを実装したT>に対してOption<Tの中身の可変参照>を返す。[/2025-08-22] →as_deref_mutの使用例 |
||
as_slice(&self) ->
&[T] |
|||
as_mut_slice(&mut
self) -> &mut [T] |
|||
map<U, F>(self, f: F) ->
Option<U> |
Option<T>をOption<U>に変換する。 | let opt = Some(123); |
|
map_or<U, F>(self,
default: U, f: F) -> U |
|||
map_or_else<U,
D, F>(self, default: D, f: F) -> U |
|||
inspect<F>(self, f:
F) -> Self |
|||
ok_or<E>(self, err: E)
-> Result<T, E> |
Option<T>をResult<T, E>に変換する。 | let opt = Some(123); |
|
ok_or_else<E,
F>(self, err: F) -> Result<T, E> |
|||
iter(&self) -> Iter<'_,
T> |
|||
iter_mut(&mut self)
-> IterMut<'_, T> |
|||
filter<P>(self,
predicate: P) -> Self |
Someのとき、Pを満たせば自分自身を返す。満たせなかったらNoneを返す。 | let some = Some(123); |
|
and<U>(self, optb:
Option<U>) -> Option<U> |
Someをtrue、Noneをfalseに見立てた論理積。 | ||
and_then<U,
F>(self, f: F) -> Option<U> |
|||
or(self, optb: Option<T>)
-> Option<T> |
Someをtrue、Noneをfalseに見立てた論理和。 | ||
or_else<F>(self, f:
F) -> Option<T> |
|||
xor(self, optb:
Option<T>) -> Option<T> |
Someをtrue、Noneをfalseに見立てた排他的論理和。 | ||
insert(&mut self,
value: T) -> &mut T |
|||
get_or_insert(&mut
self, value: T) -> &mut T |
|||
get_or_insert_default(&mut self) -> &mut T |
|||
get_or_insert_with<F>(&mut self, f: F) -> &mut T |
|||
take(&mut self) ->
Option<T> |
値の所有権を奪う。 元のOptionはNoneに変わる。 |
struct MyStruct { |
|
take_if<P>(&mut
self, predicate: P) -> Option<T> |
|||
replace(&mut self,
value: T) -> Option<T> |
|||
zip<U>(self, other:
Option<U>) -> Option<(T, U)> |
|||
zip_with<U, F,
R>(self, other: Option<U>, f: F) -> Option<R> |
その他に、Option<T>のTが特定の条件の場合だけ使用できるメソッドもある。
TがCloneトレイトを実装していると、Optionでcloneメソッドが使用できる。
clone(&self) -> Self
「Some(t)
」に対して「Some(tのクローン)
」が欲しい時に便利。
use std::rc::Rc; // RcはCloneを実装している struct MyStruct; let rc = Rc::new(MyStruct {}); let opt: Option<Rc<MyStruct>> = Some(rc); let clo: Option<Rc<MyStruct>> = opt.clone();
クローン(複製)したので、cloはoptとは別の所有権になる。
Tが参照でCloneトレイトを実装している場合は、clonedメソッドが使用できる。[2025-08-21]
clonedメソッドは、Option<&U>に対してOption<U>を返す。(UがCloneトレイトを実装している必要がある)
型とメソッド | 戻り値の型 | 例 | |
---|---|---|---|
Option<String> |
clone() |
Option<String> |
let s: String = "abc".to_string(); |
cloned() |
不可(コンパイルエラー) | ||
Option<&String> |
clone() |
Option<&String> |
let s: String = "abc".to_string(); |
cloned() |
Option<String> |
let s: String = "abc".to_string(); |
|
Option<&mut String> |
clone() |
不可(コンパイルエラー) (可変参照は同時に1つしか存在できないため) |
|
cloned() |
Option<String> |
let mut s: String = "abc".to_string(); |
Option<Result<T, E>>だと、Optionでtransposeメソッドが使用でき、Result<Option<T>, E>に変換できる。
transpose(self) -> Result<Option<T>, E>
let opt: Option<Result<i32, String>> = Some(Ok(123)); let r: Result<Option<i32>, String> = opt.transpose();
Option<Option<T>>だと、Optionでflattenメソッドが使用できる。
flatten(self) -> Option<T>
let opt = Some(Some(123)); let flat = opt.flatten(); assert_eq!(Some(123), flat);
Tが演算子用のPartialOrdやPartialEqトレイト等を実装していると、Optionのまま大小比較や等値比較が出来る。
この場合、Noneが最小の値として扱われる。
let some = Some(123); let s100 = Some(100); let none: Option<i32> = None; assert_eq!(true, s100 < some); assert_eq!(true, none < s100);
Resultで「?演算子」が使えるのと同様に、Optionでも?演算子を使うことが出来る。
Optionの?演算子は、Someのときはそれが保持している値を返し、NoneのときはNoneをreturnする(関数からNoneを返す)。
fn func1() -> Option<i32> { let n = func2()?; Some(n + 1) }
fn func2() -> Option<i32> { None }
Optionから値を取得する例。[2025-08-22]
方法 | 例 | 説明 |
---|---|---|
unwrap |
fn func(o: Option<i32>) { let n = o.unwrap(); // n: i32 println!("{}", n); } |
Optionから値を取得するにはunwrap系メソッドを使う。 (JavaのOptional.get()相当) |
?演算子 |
fn func(o: Option<i32>) -> Option<String> { let n = o?; // n: i32 println!("{}", n); 〜 } |
「Optionから値を取得する処理」を囲んでいる関数がOptionを返す場合は、?演算子で値を取得できる。 |
take |
struct MyStruct { value: Option<String>, } impl MyStruct { fn test(&mut self) { println!("before {:?}", self.value); let t = self.value.take(); // t: Option<String> println!("take {:?}", t); println!("after {:?}", self.value); // None } } |
takeメソッドは、Optionの内容を取得して、元のOptionの中身をNoneに更新する。 |
match |
fn func(o: Option<i32>) { match o { Some(n) => println!("{}", n), None => println!("none"), } } |
Optionの内容によって処理を分岐する。 |
if let |
fn func(o: Option<i32>) { if let Some(n) = o { println!("{}", n); } } |
値が存在しているときだけ処理を行う。 |
参照 |
fn func(o: Option<String>) { match &o { Some(s) => println!("{}", s), // s: &String None => println!("none"), } println!("{:?}", o); // 2つめのprintln } |
Optionの値を参照で取得する例。 左記の例で「 match o { Some(s) => 」とすると、そこでoの所有権を奪ってしまうので、2つめのprintlnでoを使用できずコンパイルエラーになる。 |
fn func(o: Option<String>) { match o.as_ref() { Some(s) => println!("{}", s), // s: &String None => println!("none"), } println!("{:?}", o); // 2つめのprintln } |
||
fn func(o: Option<String>) { match o { Some(ref s) => println!("{}", s), // s: &String None => println!("none"), } println!("{:?}", o); // 2つめのprintln } |
構造体のOptionフィールドを取得する例。[2024-10-03]
struct MyCommon {} struct MyOpt { field: Option<MyCommon> } let mut opt = MyOpt { field: None }; opt.field = Some(MyCommon {});
フィールドの型 | 取得する型 | 例 | 備考 |
---|---|---|---|
Option<MyCommon> |
MyCommon |
let r = opt.field.unwrap(); |
unwrapを使うと所有権を奪うので、それ以降opt.fieldは使用できない。 |
Option<MyCommon> |
Option<MyCommon> |
let r = opt.field; |
所有権が変数に移動するので、それ以降opt.fieldは使用できない。 |
let r = opt.field.take(); |
takeを使うと所有権を獲得する。 opt.fieldはNoneに変わり、opt.fieldはNoneの所有者になる。 |
||
Option<MyCommon> |
Option<&MyCommon> |
let r = opt.field.as_ref(); |
Option<不変参照>を取得する。 |
Option<MyCommon> |
Option<&mut MyCommon> |
let r = opt.field.as_mut(); |
Option<可変参照>を取得する。 |
Option<MyCommon> |
&MyCommon |
let r = opt.field.as_ref().unwrap(); |
不変参照を取得する。 |
Option<MyCommon> |
&mut MyCommon |
let r = opt.field.as_mut().unwrap(); |
可変参照を取得する。 |
impl MyOpt { pub fn field(&self) -> Result<&MyCommon, &str> { self.field.as_ref().ok_or("field is None") } pub fn field_mut(&mut self) -> Result<&mut MyCommon, &str> { self.field.as_mut().ok_or("field is None") } }
struct MyOpt<'a> { field: Option<&'a MyCommon>, } let mut opt = MyOpt { field: None }; opt.field = Some(&MyCommon {});
フィールドの型 | 取得する型 | 例 | 備考 |
---|---|---|---|
Option<&MyCommon> |
Option<&MyCommon> |
let r = opt.field; |
Option<不変参照>を取得する。 不変参照では参照をコピーするので、フィールドの所有権を奪わない. |
let r = opt.field.as_deref(); |
Option<不変参照>を取得する。 | ||
Option<&MyCommon> |
&MyCommon |
let r = opt.field.unwrap(); |
不変参照を取得する。 |
let r = opt.field.as_deref().unwrap(); |
impl<'a> MyOpt<'a> { pub fn field(&self) -> Result<&MyCommon, &str> { self.field.ok_or("field is None") } }
struct MyOpt<'a> { field: Option<&'a mut MyCommon>, } let mut opt = MyOpt { field: None }; let mut common = MyCommon {}; opt.field = Some(&mut common); // 可変参照の場合、直接「&mut MyCommon{}」とは書けない
フィールドの型 | 取得する型 | 例 | 備考 |
---|---|---|---|
Option<&mut MyCommon> |
Option<&MyCommon> |
let r = opt.field.as_deref(); |
Option<不変参照>を取得する。 |
Option<&mut MyCommon> |
Option<&mut MyCommon> |
let r = opt.field.as_deref_mut(); |
Option<可変参照>を取得する。 |
let r = opt.field; |
Option<可変参照>を取得できるが、可変参照ではフィールドの所有権が変数に移動する。 | ||
Option<&mut MyCommon> |
&MyCommon |
let r = opt.field.as_deref().unwrap(); |
不変参照を取得する。 |
Option<&mut MyCommon> |
&mut MyCommon |
let r = opt.field.as_deref_mut().unwrap(); |
可変参照を取得する。 |
impl<'a> MyOpt<'a> { pub fn field(&self) -> Result<&MyCommon, &str> { self.field.as_deref().ok_or("field is None") } pub fn field_mut(&mut self) -> Result<&mut MyCommon, &str> { self.field.as_deref_mut().ok_or("field is None") } }
Cloneトレイトを実装しているRcの例。
use std::rc::Rc; struct MyOpt { field: Option<Rc<MyCommon>>, } let mut opt = MyOpt { field: None }; opt.field = Some(Rc::new(MyCommon {}));
フィールドの型 | 取得する型 | 例 | 備考 |
---|---|---|---|
Option<Rc<MyCommon>> |
Option<Rc<MyCommon>> |
let r = opt.field.clone(); |
クローン(複製)された新しいインスタンスのOptionを取得する。 フィールドの所有権は元のまま変わらない。 |
impl MyOpt { pub fn field(&self) -> Result<Rc<MyCommon>, &str> { self.field.clone().ok_or("field is None") } }