値が存在しない場合があるような状況では、オプショナルを使用します。オプショナルとは、以下のどちらかです。
- 値があり、x と等しい
または
- 値が無い
nil
を返すようにできることです。しかしながら、これはオブジェクトでのみ有効で、構造体や、C の型、列挙型の値ではできません。これらの型では、Objective-C のメソッドは値が存在しないことを示すための(NSNotFound
のような)特別な値を返すようにします。このアプローチは、メソッドを呼び出す側が特別な値があることを把握していることを前提としています。Swift のオプショナルは、特別な定数を必要とせずに、どんな型に対してでも値が存在しないことを示します。
この例では、値が存在しないことに対処するために、オプショナルがどのように使われるかを示す例です。Swift の Int
型には、String
値を Int
値に変換するイニシャライザがあります。しかし、あらゆる文字列が整数に変換できるわけではありません。文字列 "123"
は、数値 123
に変換できますが、文字列 "hello, world"
は数値に変換できません。
次の例は、String
を Int
に変換するイニシャライザを使用しています。
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber は "Int?" 型、あるいは "optional Int" と推論される
イニシャライザが失敗する場合があるため、Int
ではなく、オプショナル Int
を返します。オプショナル Int
は、Int
でなく、Int?
と記述します。クエスチョンマークは、値がオプショナルであることを示します。つまり、Int
値を含んでいるか、または値が存在しないことを意味します。(Bool
値や String
値にはなりえず、Int
または存在しないのいずれかです。)
nil
オプショナル変数に特別な値 nil
を代入して、値が存在しない状態にします。
var serverResponseCode: Int? = 404
// serverResponseCode は Int 値 404
serverResponseCode = nil
// serverResponseCode には値が存在しない
nil
をオプショナルでない定数や変数に使うことはできません。定数または変数が、ある条件において値が存在しない状態を扱う必要がある場合は、適切な型のオプショナル値として宣言してください。
デフォルト値を指定せずにオプショナル変数を定義する場合、その変数には自動的に nil
が設定されます。
var surveyAnswer: String?
// surveyAnswer は自動的に nil に設定される
nil
は、Objective-C での nil
と同じではありません。Objective-C では、nil
は存在しないオブジェクトのポインタです。Swift では、nil
はポインタではなく、ある型の値が存在しないことです。オブジェクトだけでなく、どんな型のオプショナルにでも nil
を設定することが可能です。
If 文と強制アンラップ
オプショナルが、nil
ではなく、値を保持しているかどうかを調べるために、if
文を使うことができます。「等価」演算子 (==
) または「不等価」演算子 (!=
) で比較を行います。
オプショナルに値がある場合、nil
に対して「不等価」とみなされます。
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// "convertedNumber contains some integer value." と出力
オプショナルが値を保持していることを確認した後は、オプショナルの名前の末尾にエクスクラメーションマークを付加して値にアクセスできます。このエクスクラメーションマークは、「このオプショナルが間違いなく値を保持していることがわかっているので、その値を使用する」ということを意味します。これをオプショナル値の強制アンラップと呼びます。
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// "convertedNumber has an integer value of 123." と出力
if
文についての詳細は、Control Flow で確認してください。
!
でアクセスしようとすると、実行時エラーになります。!
を使ってオプショナル値を強制アンラップする前に、nil
でないことを常に確認してください。
オプショナルバインディング
オプショナルが値を保持しているかを確認するために、オプショナルバインディングを使用し、その値を一時的な定数として利用できるようにします。オプショナルバインディングは、オプショナルが値を保持していることを確認するために、if
および while
文で使用することができます。と同時に、そこで抽出した値を定数に代入します。if
および while
文についての詳細は、Control Flow で説明されています。
以下のように、if
文にオプショナルバインディングを記述します。
if let constantName = someOptional {
statements
}
Optionals セクションにある possibleNumber
の例を、強制アンラップではなく、オプショナルバインディングを使って書き直すことができます。
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an integer")
}
// "'123' has an integer value of 123" と出力される
このコードは、「Int(possibleNumber)
によって返されるオプショナルの Int に値がある場合は、そのオプショナルが保持している値を新たな定数 actualNumber
に設定する」と読むことができます。
変換が成功する場合、定数 actualNumber
を if
文の初めの分岐内で利用できるようになります。オプショナルが保持している値ですでに初期化されているので、!
を付けて値にアクセスする必要はありません。この例では、actualNumber
は単に変換の結果を出力するために利用されています。
1 つの if
文に複数のオプショナルバインディングを含めることができ、ブール条件をチェックするために where
節を使うことができます。オプショナルバインディングの値が 1 つでも nil
である場合や、where
節が false
となる場合は、オプショナルバインディング全体が成立しなかったとみなされます。
if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)")
}
// "4 < 42" と出力される
if
文のオプショナルバインディングによる定数は、if
文の本体でのみ利用することができます。対照的に、guard
文による定数は、Early Exit で説明しているように、guard
文の後に続くコード行で利用できます。
無条件アンラップ
上で述べているように、オプショナルは、定数や変数に値が存在しない場合があることを示しています。オプショナルは、値が存在するかを if
文でチェックすることができ、値が存在する場合はオプショナルバインディングでオプショナル値にアクセスして条件付きでアンラップすることができます。
値が設定された後など、オプショナルが常に値が持っていることが、プログラムの構成から明らかな場合もあります。こういったケースでは、常に値があることを前提にして、アクセスのたびにオプショナル値をチェックしてアンラップする処理を削除するほうが効果的です。
こういったオプショナルは、無条件にアンラップされるオプショナルとして定義されます。オプショナルにしたい型の直後にクエスチョンマーク (String?
) を置くのではなく、エクスクラメーションマーク (String!
) を置いて無条件にアンラップされるオプショナルを記述します。
無条件にアンラップされるオプショナルは、オプショナルが初めに定義された直後で、その後も値が存在していることがあきらかなオプショナル値の場合に効果的です。Swift での主要な用途は、クラスの初期化処理で、Unowned References and Implicitly Unwrapped Optional Properties で説明されています。
無条件にアンラップされるオプショナルは、通常のオプショナルですが、アクセスのたびにオプショナル値をアンラップすることなく、オプショナルでない値のように使うことができます。次の例は、ラップされた String
の値にアクセスするとき、オプショナル文字列と、無条件にアンラップされるオプショナル文字列との間での動作の違いを示しています。
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // エクスクラメーションマークが必要
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // エクスクラメーションマークは不要
無条件にアンラップされるオプショナルを、使用時に自動的にアンラップされることが許可されているオプショナルとして考えることができます。使用するたびにオプショナル名にエクスクラメーションマークを付けるのではなく、宣言時にオプショナルの型にエクスクラメーションマークを付けます。
nil
のときに、ラップされている値にアクセスしようとすると、実行時エラーになります。これは、値が存在しない通常のオプショナルに、エクスクラメーションマークを付けた場合とまったく同じ結果です。
値の有無をチェックするために、無条件にアンラップされるオプショナルを、通常のオプショナルと同じように扱うことができます。
if assumedString != nil {
print(assumedString)
}
// "An implicitly unwrapped optional string." と出力
1 文で値をチェックしてアンラップするために、無条件にアンラップされるオプショナルに、オプショナルバインディングを使うこともできます。
if let definiteString = assumedString {
print(definiteString)
}
// "An implicitly unwrapped optional string." と出力
nil
になりえる場合は、無条件にアンラップされるオプショナルを使用しません。変数が nil
かどうかチェックする必要がある場合には、常に通常のオプショナル型を使用します。
Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.