Optional<Wrapped>型とは
Optional<Wrapped>とは、値があるか空かを示す型となります。Swiftは、通常のIntやStringで、nil(Javaなどでいうnull)を認めていません。そのため、nilが含まれる可能性のある場合は、Optional<Int>型や、Optional<String>型などを利用してnilを許容します。
Optional型がある理由は、安全性の確保です。nil を通常のInt型などに入れることによって、実行時にnilを参照しエラーになる可能性があります。Optional型を利用することによって、実行時エラーになる部分をコンパイルエラーとして先に見つけることができます。それにより安全性が確保されます。
利用方法
宣言方法
実際の、宣言方法は以下のようになります。型の後ろに?をつけることによって、Optiional<Wrapped>型であることを明記します。
var 変数名:型名?
実際の使い方としては、以下のような形になります。
var optionalNumber:Int?
var optionalString:String?
値の利用の仕方
Optional<Wrapped>型から、元のIntやStringなどの型にすることをアンラップと言います。Optional<Wrapped>型をアンラップすることによって、値を取得していきます。3つの値の取り出しかた(アンラップ)を説明していきます。さらに4つ目は、アンラップをせずに値にアクセスる方法を説明します。
1.オプショナルバインディング
if-let文を利用しOptional<Wrapped>型から値を取得する方法です。if-let文の条件式で値を取得し、取得した値を用いた処理を処理内容に記述します。これによりOptional〈Wrapped〉型にアクセスをすることができます。
if let 定数名 = Optional<Wrapped>型変数名{
処理内容
}
実際の処理は以下のような形になります。
let optionalNumber1:Int? = 1
if let num = optionalNumber1 {
print("値を取得しました:\(num)")
}
let optionalNumber2:Int? = nil
if let num = optionalNumber2 {
print("値を取得しました:\(num)")
}else{
print("値を取得できませんでした")
}
//実行結果
//値を取得しました:1
//値を取得できませんでした
オプショナルバインディングの特徴は、安全に値を取得できる点です。値があった場合のみ値を取得し、値がない場合は取得できません。そのため、nilなどが入り込まず安全に値を取得し処理を実行できます。
コード説明
if-let文について説明をします。
if let num = optionalNumber1 {
print("値を取得しました:\(num)")
}
「if let num = optionalNumber1{…}」ここで値を取得してします。ここで取得した値はnilでなければnumに代入されます。これにより、if-let文の中で値を利用することができます。
2.??演算子
??演算子とはnil合体演算子(Nil-Coalescing Operator)と呼ばれています。使い方は以下のような形です。
取得した値を保持する変数 = 変数 ?? デフォルト値
変数の値がnilであればデフォルト値になる形になります。変数をOptional〈Wrapped〉型の値にすることによってOptional〈Wrapped〉型から値を取得することができます。サンプルのソースは以下のような形になります。
let optionalNumber1:Int? = 1
let optionalNumber2:Int? = nil
let defaultValue = 0
let num1 = optionalNumber1 ?? defaultValue
let num2 = optionalNumber2 ?? defaultValue
print("num1:\(num1) num2:\(num2)")
//実行結果
//num1:1 num2:0
コード説明
let optionalNumber1:Int? = 1
let optionalNumber2:Int? = nil
変数OptionalNumber1とOptionalNumber2がOptionel<Wrapped>型の変数となります。
let num1 = optionalNumber1 ?? defaultValue //optionalNumber1の値を取得し1
let num2 = optionalNumber2 ?? defaultValue //defaultValueの値を取得し0
この部分が??を利用した、Optional〈Wrapped〉型の値を取得する処理になります
num1でoptionalNumber1で値を取得します。ここでは、optionalNumber1が1であるため、num1は1となります。次に、optionalNumber2の値を取得しますが、こちらではoptionalNumber2の値がnilであることからdefaultValueの値が、取得されnum2は0となります。このように値が存在した場合のみ値を取得することができます。
??演算子の特徴としては、値を取得する処理を簡潔に書けるという利点があります。オプショナルバインディングと比較すると値を取得するだけでなら、??演算子を利用することによって、わかりやすく簡潔に記述することができます。
3.強制アンラップ
強制アンラップとは、文字通り強制的にOptional<Wrapped>型をアンラップして値を取得します。強制的なので、たとえアンラップする変数がnilであったとしても、アンラップします。値がない場合はエラーとなる可能性があります。
強制アンラップをするためには!演算子を利用します。!演算子は、Optional<Wrapped>型を強制的にアンラップするための演算子です。
変数名!
実際の利用方法は以下のような形になります。
let optionalNumber1:Int? = 1
let optionalNumber2:Int? = nil
print("optionalNumber1:\(optionalNumber1!)") //1
print("optionalNumber2:\(optionalNumber2!)") //コンパイルエラー
コード説明
print("optionalNumber1:\(optionalNumber1!)") //1
print("optionalNumber2:\(optionalNumber2!)") //コンパイルエラー
上記の箇所で値を取得していますが、optionalNumber2!で取得した値はnilであるため、実行時にエラーとなってしまいます。
このように、強制アンラップは非常に簡潔に記述できますが、取得した値がnilである可能性があるため、エラーとなる可能性を含んでいます。そのため、絶対に値が存在する場合以外は利用を控えるのが良いです。
4.アンラップをせずに値を取得する オプショナルチェーン
Optional<Wrapped>型の値にアンラップをせずにアクセスする方法です。以下のように変数の後に?をつけ、その後ろにプロパティを指定して利用します。
変数名?.プロパティ
直接値を取得しているわけではないですが、プロパティを返して値を取得、また値を処理することができます。実際の使い方は以下のような形になります。
let optionalString:String? = "123"
if optionalString?.count != nil{
print("値が存在します")
}else{
print("値が存在しません")
}
//実行結果
//値が存在します。
コード説明
if optionalString?.count != nil{
...
}
if文の条件式、「optionalString?.count」がオプショナルチェーンを利用した値の取得の仕方になります。オプショナルチェーンの特徴として、nilであった場合には、その後のプロパティの処理をせずnilを返却するという特徴があります。
最後に
SwiftのOptional<Wrapped>型の宣言方法から使い方までをまとめました。これからも技術について発信していきますのでよろしくお願いいたします。
参考資料
Optional | Apple Developer Documentation
[増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESSプラスシリーズ)