[Swift] Optionalの使い方

C#でのNullable、scalaのOptionのようなnull値(nil値)を許容する変数を示します。

いきなりですが、下記のコードはコンパイルできるでしょうか?

var text:String = nil

javaやobjective-cの考えかただと通りますよね。
でもswiftでは通りません。
Stringにはnilを代入できなのです。

でも無いことを示したいこともありますよね。
そんな時にOptionalを使います

var text:String? = nil

Stringの後に付けた”?”がオプショナルの宣言で、値が入ってるか入ってないか分からない変数を示します。
これはStringをラップしたString?という変数という認識で良いのではないかと思います。

このOptionalな値はそのままでは使えません。
ラップしている”中身”を取り出す必要があります。
その時に使うのが !(エクスクラメーションマーク)です

var textOpt:String? = "今日もいいお天気"
let text = textOpt!

この!によってアンラップするときにもし値が存在していなかったらどうなるか?
Swiftではエラーになります。

そこで値の有無をチェックしてから取り出す事となります。


var pockyDayOpt:Int? =  "1111".toInt()

// 判定は普通にifすればOK
if pockyDayOpt {
    var pockyDay = pockyDayOpt!
    NSLog("ポッキーの日:%d",pockyDay)
} else {
    NSLog("今年はポッキーの日を中止にします。")
}

まぁ分かりやすいですが、ちょっと面倒ですよね.
そこでこんな構文でチェックとアンラップを同時に行えます


if let pockyDay = pockyDayOpt {
    NSLog("ポッキーの日:%d",pockyDay)
}

ん?まだ面倒ですか?
確かにOptionがネストしていた場合ではifがネストしてしまいちょっと面倒臭いですね。
例えばこういった構造体があったとして


struct MainDish {
    var dishName:String?
}

struct LunchBox {
    var mainDish:MainDish?
}


// ハンバーグランチ
let lunchA = LunchBox(mainDish:MainDish(dishName:"ハンバーグ"))
// 見たことも無い不思議なおかずランチ
let lunchB = LunchBox(mainDish:MainDish(dishName:nil))
// 衝撃のおかず無しランチ
let lunchC = LunchBox(mainDish:nil)

// ランチをArrayに格納
let lunches = [lunchA,lunchB,lunchC]

LunchBoxのMainDishの名前を出力する場合を考えてみます。


// 普通に書いた場合
for lunch in lunches {
    if let mainDish = lunch.mainDish {
        if let dishname = mainDish.dishName {
            NSLog("今日のランチは \(dishname) だ! やっほ~い!")
        }
        else {
            NSLog("このおかず、、、何だろ?")
        }
    }
    else {
        NSLog("おかずが無いとか。。。")
    }
}

面倒ですね。。

Swiftにはこんな時に便利なOptional-Chainという機能があります。
例を見てもらった方が早そうです。


for lunch in lunches {
    if let dishname = lunch.mainDish?.dishName {
        NSLog("今日のランチは \(dishname) だ! やっほ~い!")
    } else {
        NSLog("まともなおかず食べたい。。。")
    }
}

maindish?.dishName と記述している部分がそれです。
これはmainDishに値が設定されている場合にのみ次のdishNameが評価されます。

ifで判定せずにこんな書き方もOK


let dishName:String? = lunch.mainDish?.dishName?.lowercaseString

 
 
最後に、関数・クロージャの変数がオプショナルだった場合はこのように宣言しますよ

// 全体をカッコで囲ってオプショナルの指定を行う
var funcOpt:((String) -> (String))?

funcOpt = {
    (text:String) -> String in
    return "hello \(text)"
}

// 実行する時はこんな感じ
funcOpt!("タテオ")

 
このOptional、Optional-Chainを使うことによってヌルポが発生する機会は激減することでしょう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です