LoginSignup
3
6

More than 3 years have passed since last update.

Swiftクイズ: Optionalのアンラップ方法を思いつく限り挙げてください!

Last updated at Posted at 2021-04-02

アンラップ記事の第3弾(になってしまいました)。

はじめに

Swiftでは避けて通れないOptional型。値があるかもしれないし、無い(nil)かもしれない。
値があればその値についての何らかの処理、無ければ無かったなりの処理、と分岐することはSwiftプログラミングにおいて何度も登場することかと思います。

では、その分岐させるためのコードの書き方をいくつ知っていますか?

この記事では筆者が思いつく限りのパターンを挙げていきます(実用性の有無は問わない)。他のパターンがあればコメントしていただければ適宜追加します。

以下のコードでmaybeIntには、50%の確率でInt型の何らかの値が入っています。残りの50%はnilです。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil

maybeIntInt型の場合はその値を、nilの場合は"nilだよ。"という文字列を表示するコードを書いてください。

解答集

!= nilからの!(強制アンラップ)パターン

一番分かりやすいのはnilかどうかを!=(または==)演算子で比較してif文で分岐するというやり方でしょう。他の言語から入ってきた"Swift初心者"風の書き方です。ただ、Swiftに慣れてくると後述のoptional bindingを使うことを覚えてそちらを使うようになるかと思います。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
if maybeInt != nil {
  print(maybeInt!) // 強制アンラップを忘れずに
} else {
  print("nilだよ。")
}

三項条件演算子

printの一文で済むなら三項条件演算子を使う手もあります:

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
maybeInt != nil ? print(maybeInt!) : print("nilだよ。")

Optional Binding

Swiftにはoptional bindingという書き方があります。
if let constantName = someOptional { ... }というように書くと、someOptionalに値がある場合、その値がconstantNameに代入されif文の中身が実行されるというものです。
!= nilに比べて(強制アンラップを使わずに)簡潔に書くことができるという利点があります。

if文のoptional binding

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
if let definitelyInt = maybeInt {
  print(definitelyInt)
} else {
  print("nilだよ。")
}

guard文のoptional binding

ちなみにoptional bindingはguard文でも使えます。その場合は、else { ... }early exitが必要となる点に注意が必要です。

トップレベルでのguard

トップレベルguard.swift
let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
// トップレベルでearly exitをするために
// `exit`を使う
import CoreFoundation
// プラットフォームによってimport Darwinとimport Glibcを分ける書き方でも良い
guard let definitelyInt = maybeInt else {
  print("nilだよ。")
  exit(0)
}
print(definitelyInt)

クロージャを使ったguard

クロージャ内guard.swift
let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
({ () -> Void in
  guard let definitelyInt = maybeInt else {
    print("nilだよ。")
    return
  }
  print(definitelyInt)
})()

switch

nilかどうかはswitch文を使って判定することもできます。そのswitch文を使った書き方も何通りかあるので見ていきましょう。

case let _?を使って値を取り出す

個人的に?を使ったこのswitch-caseの書き方は当初なかなか慣れなかったのですが、こういう文法もあるのだと知っておくとどこかで役に立つかもしれません。
次のコードのようにcase式でlet _?と変数名の後に?をつけるとnilではない場合のみに文が実行されます。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
switch maybeInt {
case let definitelyInt?:
  print(definitelyInt)
case nil: // `default`でも良い
  print("nilだよ。")
}

Optionalenumであることを利用する

Optional<Wrapped>enumとして定義されており、case nonecase some(Wrapped)の二つのcaseから成ります1.nonenilのことです。次のようにenumであることを明示してswitch文を書くこともできます。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
switch maybeInt {
case .some(let definitelyInt):
  print(definitelyInt)
case .none:
  print("nilだよ。")
}

if-case

実はcase式はifでも使えます。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
if case let definitelyInt? = maybeInt {
  print(definitelyInt)
} else {
  print("nilだよ。")
}

もちろんenumとして扱うこともできます

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
if case .some(let definitelyInt) = maybeInt {
  print(definitelyInt)
} else {
  print("nilだよ。")
}

ちなみに、次のような書き方もできますが、Swiftコンパイラにバグ(SR-13904)があるため間違ったwarningが表示されます。実行に問題はありません。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
if case let definitelyInt as Int = maybeInt {
  print(definitelyInt)
} else {
  print("nilだよ。")
}

番外編

map + ??

アンラップそのものではありませんが…mapメソッド??演算子を組み合わせて、次のように同様の動作をするコードを書くこともできます。

let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
print(maybeInt.map({ $0.description }) ?? "nilだよ。")
let maybeInt: Int? = Bool.random() ? Int.random(in: .min ... .max) : nil
maybeInt.map({ print($0) }) ?? print("nilだよ。")

おわりに

Optionalのアンラップ方法はいくつもあることがお分かりいただけたでしょうか。二重三重のOptional(たとえばInt??とかString???とか)を扱う場合はcaseを使うほうが便利な場合があります。

この記事を読んで読者の方々のSwiftコードの書き方の幅が広がれば幸いです。

3
6
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
3
6