Swiftの三項演算子(ternary operator)

三項演算子

ここでは、おそらく演算子の最難関である三項演算子について紹介していきます。

三項演算子に関しては、基本的には別の評価演算のショートカットですから、使えなくても困ることはありません。ただ、2条件分岐の際にはコードを綺麗にすることができますので、使いこなせると(見た目が美しくなるという意味で)満足できるかもしれません。また、正確には二項演算子なのですが、Nil合体演算子(Nil Coalescing Operator)に関しても紹介したいと思います。

三項演算子(ternary operator)

三項演算子の基本構造

三項演算子(Ternary Operator)は特殊な演算子で、以下のような評価式を使います。

question ? answer1 : answer2

最初のquestionはブール値で、ここがtrueならばanswer1を返し、falseならばanswer2を返します。

この演算子は次のようなif文のショートカットになっています。

// 3項演算子をif文で置き換え
if question {
  answer1
} else {
  answer2
}

if文にすると理解しやすいのではないかと思います。answer1answer2は定数・変数単体だけでなく、演算を組み合わせた評価式でも構いません。

三項演算子の使用例

以下三項演算子の使用例です。

// 時刻を表示(3項演算子)
let whatTimeNow = "現在の時刻は"
let currentHour = 14 // 午後2時
let isMorning = currentHour < 12
let tellTime = whatTimeNow + (isMorning ? "午前" : "午後") + "\(currentHour%12)時です"
print(tellTime)
// "現在の時刻は午後2時です"と表示

if文にすると

// 時刻を表示(if文)
let whatTimeNow = "現在の時刻は"
let currentHour = 14 // 午後2時
let isMorning = currentHour < 12
var tellTime = whatTimeNow
if isMorning {
  tellTime += "午前\(currentHour%12)時です"
} else {
  tellTime += "午後\(currentHour%12)時です"
}
print(tellTime)
// "現在の時刻は午後2時です"と表示

という具合になります。

正午が表示できないので、余りいい例ではありませんが、現在の時間から午前と午後を判断して時刻を表示します。三項演算子を使ってプログラミングすると、if文に比べて簡潔に表現できています。if文を用いると、どうしても中間に変数(ここではtellTime)を挟まないといけません。三項演算子を用いれば処理を一行で表現できるので、tellTimeを定数として宣言することが可能です。

三項演算子の表現は慣れないとちょっと複雑ですが、2つの条件から選ぶような場合は便利です。


補足:
三項演算子は条件分岐を簡潔に表現できるので便利ですが、多用するとコードが読みにくくなるので慎重に使いましょう、と公式マニュアルでは注意書きがあります。

“The ternary conditional operator provides an efficient shorthand for deciding which of two expressions to consider. Use the ternary conditional operator with care, however. Its conciseness can lead to hard-to-read code if overused. Avoid combining multiple instances of the ternary conditional operator into one compound statement.”

抜粋:: Apple Inc. “The Swift Programming Language”。 iBooks https://itun.es/jp/jEUH0.l


Nil合体演算子(Nil Coalescing Operator)

Nil合体演算子(Nil Coalescing Operator)とはどんな演算子でしょうか?Coalesce(コアレス)なんて聞いたこともない単語ですが、くっつくとか合体するという意味だそうです。nilに関係する演算だろうということは予想できます。実際に見てみましょう。

Nil合体演算子の基本構造

Nil合体演算子(a ?? b)は、公式マニュアルによると次のような三項演算のショートカットになります。

// Nil Coalescing Operator
(a != nil) ? a! : b

分かりやすくするために、かっこ()を足してます。

if文にしてみると、

// Nil Coalescing Operatorをif文で表現
if a != nil {
  a!
} else {
  b
}

となります。これはif文での構造だけを表現したもので、Swiftとしての文法は無視しています。Nil合体演算子は二項演算子(binary operator)ですが、実体としてはternaryですので三項演算子として区分けしました。

Nil合体演算子を文章にすると

となります。

Nil合体演算子の使用例

基本的な使い方としては、「何かデフォルトの振る舞いを指定しておいて(b)、オプションとしての振る舞い(a)はユーザが任意で選択できるようにする」といった感じになります。

// Nil Coalescing Operatorの使用例
let pageTitle = "Nil Coalescing Operator"
let defaultSlug = pageTitle
var userDefinedSlug: String? // デフォルトではnil
let slug = userDefinedSlug ?? defaultSlug
print(slug)
// "Nil Coalescing Operator"と表示

上記の例では、「webページURLとして、デフォルトではページのタイトルを使用し、もしユーザが指定すればそちらを採用する」という機能を簡単に表現したものです。今userDefinedSlugnilですので、使うURLとしてはデフォルトのdefaultSlugが採用されます。

試しにuserDefinedSlugを変更してみると

// userDefinedSlugを変更
userDefinedSlug = "nil-coalescing-operator"
let slug = userDefinedSlug ?? defaultSlug
print(slug)
// "nil-coalescing-operator"と表示

となり、変更がちゃんと反映されていることが分かります。また、公式マニュアルによると、Nil合体演算子にも短絡評価が組み込まれていて、anilでない場合bは評価されません。

まとめ

  • 三項演算子はquestion ? answer1 : answer2という評価式を使う
  • questionはブール値で、trueならanswer1falseならanswer2を返す
  • Nil合体演算子a ?? bは、三項演算(a!=nil) ? a! : bのショートカット