[Swift] Optional型についてのまとめ


この記事は一部内容が古くなったので、全面的に書き直した記事を別にあげました（14/10/17 追記）。
↓
[[Swift] Optional 型についてのまとめ Ver2](http://qiita.com/cotrpepe/items/518c4476ca957a42f5f1)


# Optional型とは？

* Optional型 : nilが入るのを許す
* 非Optional型 : nilが入るのを許さない


# Optional型の宣言方法

```swift
var a: Int? // Optional型
var b: Int  // 非Optional型

var c: String? // Optional型
var d: String  // 非Optional型
```


# ```T?```は、```Optional<T>```のシンタックスシュガーである

```swift
var a: Int?
var b: Optional<Int> // Int?と同じ意味
```


# Optional型はnilが代入されるのを許す

```swift        
var a: Int? // Optional型
a = nil     // コンパイラエラーは発生しない
 
var b: Int // 非Optional型
b = nil    // コンパイラエラーが発生する: Could not find an overload for '__conversion' that accepts the supplied arguments
```


# Optional型の初期値は```nil```

Optional型の初期値は```nil```である。

```swift
var a: Int? // Optional型
println(a)  // -> nil
```

非Optional型の場合、初期値には何も入っていない（```nil```も入っていない）。

```swift
var b: Int // 非Optional型
println(b) // コンパイラエラーが発生する: Variable 'b' used before being initialized
```


# Optional型は、非Optional型と同じようには扱えない

```swift
var a: Int = 1
println(a + 2) // -> 3
 
var b: Int? = 1
println(b + 2) // コンパイラエラーが発生する: Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
```

上記のとおり、```Int?```は、```Int```とは別の型なので、同じように操作することはできない。```Int```と同じように扱うためには、変数を「アンラップ」する必要がある（後述）。


# ラップ（wrap）とアンラップ（unwrap）

## 「ラップされている」とは？

Optional型（```Optional<T>```型）の変数のことを「ラップされている」と言う（おそらく、```Optional<T>```型に```T```型の変数が包まれていることに由来すると思われる）

## 「アンラップする」とは？

Optional型（```Optional<T>```型）から```T```型の変数を取り出すことを、「アンラップする」と言う。


# Optional型の変数をアンラップする方法

Optional型の変数をアンラップするには、以下の方法がある。

1. Forced Unwrapping
2. Optional Chaining
3. Optional Binding
4. Implicitly Unwrapped Optional型


# 1. Forced Unwrapping

以下のように、```!```を使って、Optional型の変数をアンラップすることができる。

```swift
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}

var d: Dog? = Dog() // Optional型

// ラップされた状態のままでは、barkメソッドを呼び出すことができない
println(d.bark()) // コンパイラエラーが発生する: 'Dog?' does not have a member named 'bark'

// 変数dのうしろに「!」を付けることで、アンラップすることができる（Forced Unwrapping）
println(d!.bark()) // -> Wan!

// 変数dの中身がnilだった場合は、「!」でアンラップする際にランタイムエラーが発生する
d = nil
println(d!.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None
```


# 2. Optional Chaining

以下のように、```!```ではなく```?```を使ってアンラップすることを「Optional Chaining」と言う。

```swift
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}

var d: Dog? = Dog() // Optional型

// 変数dのうしろに、「?」を付けるとアンラップされる（Optional Chaining）
println(d?.bark()) // -> Wan!

// 変数dにnilが入っていた場合、アンラップ時にnilが返ってくる
d = nil
println(d?.bark()) // -> nil
```

Forced Unwrapping（```!```を使う方法）と違い、```nil```に対してアンラップをしても、ランタイムエラーは発生しない。代わりに、```nil```が返ってくる。

## 注意：`println` について（14/10/17 追記）

`println(d?.bark())` の出力結果が、最新版の xcode と異なるので、注意してください。

* Xcode 6 Beta の場合（この記事の執筆に使ったバージョン）

```swift
println(d?.bark()) // -> Wan!
```

* Xcode 6.1 GM seed 2 の場合

```swift
println(d?.bark()) // -> Optional(Wan!)
```

`println` で optional 型の変数を出力するときに、`Optional()` という文字列が付加されるようになりました。


# 3. Optional Binding

if文やwhile文の条件式で宣言され、Optional型の変数を代入された変数は、非Optional型になる。これを「Optional Binding」と言う。

```swift
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}

var wrappedDog: Dog? = Dog() // Optional型

// if文の条件式で宣言された変数は、非Optional型になる（Optional Binding）
if var unwrappedDog1 = wrappedDog {
	// 「!」を付ける必要はない
    println(unwrappedDog1.bark()) // -> Wan!
}

// 「var」と「let」のどちらで宣言してもかまわない
if let unwrappedDog2 = wrappedDog {
    println(unwrappedDog2.bark()) // -> Wan!
}

// while文でもOptional Bindingが利用できる
while var unwrappedDog3 = wrappedDog {
    println(unwrappedDog3.bark()) // -> Wan!
    break
}


//////////
// 補足1 //
//////////

//
// 上記の変数「unwrappedDog1」「unwrappedDog2」「unwrapedDog3」は、ブロック内でのみ有効
//
println(unwrappedDog1.bark()) // コンパイラエラーが発生する: Use of unresolved identifier 'unwrappedDog1'
println(unwrappedDog2.bark()) // コンパイラエラーが発生する: Use of unresolved identifier 'unwrappedDog2'
println(unwrappedDog3.bark()) // コンパイラエラーが発生する: Use of unresolved identifier 'unwrappedDog3'


//////////
// 補足2 //
//////////

//
// wrappedDog変数がnilの場合は、if文の条件式の結果がfalseになるので、ブロック内の処理は実行されない。
//
wrappedDog = nil
if var unwrappedDog4 = wrappedDog {     // falseになる
    println("This is not printed out.") // -> 出力されない
}
```


# 4. Implicitly Unwrapped Optional型

Optional（```Optional<T>```）型ではなく、Implicitly Unwrapped Optional型を使うと、暗黙的にアンラップすることができる。変数をImplicitly Unwrapped Optional型で宣言する際には、```?```ではなく、```!```を使う。

```swift
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}

// 「?」ではなく、「!」を使って宣言する
var d: Dog! = Dog() // Implicitly Unwrapped Optional型

// アンラップ操作は不要（暗黙的にアンラップされる）
println(d.bark()) // -> Wan!

// 変数dの中身がnilだった場合、暗黙的なアンラップ時にランタイムエラーが発生する
d = nil
println(d.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None   
```


# ```T!```は、```ImplicitlyUnwrappedOptional<T>```のシンタックスシュガーである

```swift
var a: Int! // Implicitly Unwrapped Optional型
var b: ImplicitlyUnwrappedOptional<Int> // Int!と同じ意味
```


# Optional型とImplicitly Unwrapped Optional型との違い（まとめ）

|型                             |宣言方法|型の実体                         |アンラップ時の操作|
|:------------------------------|:--|:----------------------------------|:-----------|
|Optional型                     |```var a: T?```|```Optional<T>```                   |明示的な操作が必要|
|Implicitly Unwrapped Optional型|```var a: T!```|```ImplicitlyUnwrappedOptional<T>```|不要（暗黙的にアンラップされる|


# ```nil```に対して、アンラップをした場合の挙動（まとめ）

## Optional（```Optional<T>```）型の場合

|アンラップの方法|結果|
|:--|:--|
|Forced Unwrappingの場合（```!```を使う方法）|ランタイムエラーが発生する|
|Optional Chainingの場合（```?```を使う方法） |```nil```が返ってくる         |

```swift
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}

var d: Dog? = nil // Optional型

// Forced Unwrappingの場合（!を使う場合）
println(d!.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None

// Optional Chainingの場合（?を使う場合）
println(d?.bark()) // -> nil
```

## Implicitly Unwrapped Optional型（```ImplicitlyUnwrappedOptional<T>```）型の場合

|アンラップの方法|結果|
|:--|:--|
|暗黙的にアンラップされる|ランタイムエラーが発生する|

```swift
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}

var d: Dog! = nil // Implicitly Unwrapped Optional型
println(d.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None   
```


# 開発環境
* Xcode 6 Beta
* Mac OS X 10.9.3


# 実行環境
* iOS Simulator (iPhone5s / iOS 8.0)


# 参考文献

[The Swift Programming Language]
(https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-XID_0)

[Facets of Swift, Part 1: Optionals]
(https://medium.com/@tammofreese/facets-of-swift-part-1-optionals-b8ba5b0051a2)

[stakoverflow - What does an exclamation mark mean in the Swift language?]
(http://stackoverflow.com/questions/24018327/what-does-an-exclamation-mark-mean-in-the-swift-language)

[先取り！Swift]
(http://dev.classmethod.jp/smartphone/iphone/forestalling-swift/)

[Wikipedia - Swift (プログラミング言語)]
(http://ja.wikipedia.org/wiki/Swift_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E))