LoginSignup
251
249

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-07-07

この記事は一部内容が古くなったので、全面的に書き直した記事を別にあげました(14/10/17 追記)。

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

Optional型とは?

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

Optional型の宣言方法

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

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

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

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

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

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である。

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

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

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

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

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型の変数をアンラップすることができる。

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」と言う。

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 の場合(この記事の執筆に使ったバージョン)
println(d?.bark()) // -> Wan!
  • Xcode 6.1 GM seed 2 の場合
println(d?.bark()) // -> Optional(Wan!)

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

3. Optional Binding

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

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型で宣言する際には、?ではなく、!を使う。

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>のシンタックスシュガーである

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が返ってくる
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>)型の場合

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

Facets of Swift, Part 1: Optionals

stakoverflow - What does an exclamation mark mean in the Swift language?

先取り!Swift

Wikipedia - Swift (プログラミング言語)

251
249
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
251
249