本日からは Swift の 演算子
について見ていきますね。そのうちでも基本的な演算子について綴られた Basic Operators の章に沿って見渡していく予定です。よろしくお願いしますね。
———————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #315
00:00 Start 00:17 今回の展望 01:16 基本的な演算子 02:00 演算子とは 03:05 二項代入演算子 04:40 単項後置演算子 05:10 二項中置加算演算子 05:37 フレーズによる演算子 08:14 as や = は関数としては存在しない様子 09:48 演算子の具体的表現 11:15 Swift にある演算子 12:27 代入演算子は戻り値を返さない 15:26 代入演算子の複雑な使用を制限して安全性を高めている 17:44 代入演算は組み込みの様子 19:19 返す値がないだけのときと、本当に処理が返らないときと 21:45 本当に値がない場合 27:13 戻り値がなくても実行の成否を判定可能 31:51 クロージング ————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #315
今日は「The Swift Programming Language」というAppleの公式ドキュメントに沿って、Swiftの基本演算子について学びます。この勉強会では、たまに脱線することがありますが、それも含めて楽しんでいただければ幸いです。質問や気になることがあれば、自由にコメントしていただいて構いません。
さて、まずは「演算子」についてです。基本演算子といっても、特に新しい言葉ではありません。Swiftの公式ドキュメントに基づいて話を進めます。演算子とは、値を検査したり、変更したり、合成したりする場合に使われる特殊な記号やフレーズのことです。プログラミング言語全般に言えることですが、命令はこうした操作を行います。
Swiftには代入演算子や比較演算子など、さまざまな演算子があります。例えば、イコール(=
)は代入演算子の一つです。普通のプログラミング言語と同様に、関数やメソッドの呼び出し方もありますが、Swiftの演算子は言語構文の一部として特別に入力できるという基本的な動きを持っています。例えば、値が構造体ならコピーし、+
といった記号で結合操作が行えます。ビックリマーク(!
)は強制アンラップとして、オプショナル型に対する演算子です。
演算子には、単項演算子や二項演算子があります。単項演算子は一つの項に対して作用するもので、二項演算子は二つの項を操作します。例えば、+
や-
は二項演算子です。
さらに、演算子にはフレーズとして表現できるものもあります。例えば、型を変換する際のas
です。他にも、様々な演算子が存在しますが、全部を網羅するのはここでは控えておきます。
Swiftの演算子は、ライブラリにより提供されるメソッドに比べて、より自然で読みやすいコードを書けるようにサポートしています。様々な演算子の使い方に慣れて、効率よくSwiftプログラムを書けるようになることを目指しましょう。演算子の話を続けていく中で、後に続く独自の演算子についての説明もあるかもしれませんが、それはおいおい触れていきます。
本日はそんな感じで特殊な記号やフレーズで構成される、演算子についてのお話でした。 加算演算子プラスは、2つの値を加えるためのものです。例えば、1 + 2
のように使いますね。日常でも親しみのあるこの記号を演算子と呼びます。
次に、論理的演算子の&&
(アンドアンド)は、2つの真偽値を組み合わせて1つの真偽値を生成します。基本情報技術の試験などを受けたことがある人には馴染みのある"これかつこれ"という条件を表します。両方の真偽値がtrue
のときにtrue
を返すという演算子です。他にも多くの演算子が存在しますが、それについては後ほど説明します。
他にもさまざまな演算子がある中で、SwiftにはC言語のようなよく知られた言語の演算子に加えて、一般的なコーディングエラーを排除するためのいくつかの機能改善がされています。これがSwiftの特徴の1つで、本当に興味深いところです。プログラミング言語にはそれぞれよくある間違いというものがあって、それを反面教師として得たノウハウを新しい言語に盛り込んでいこうという考え方があります。Swiftも登場から時間が経ち、少し古めかしくなってきたかもしれませんが、こだわり続けているポイントの紹介の一部がこれです。
代入演算子=
は戻り値を返さないようにして、誤って比較演算子==
と混同されることを防ぐことができます。C言語を使っている人にはよくある間違いですが、最近のプログラミングを始めた人にとっては馴染みがないかもしれません。例えば、let x = 10
やlet y = 20
の後にif x == y
のように書くことが一般的です。しかし、C言語ではうっかり=
を使って代入してしまうことがあります。
Swiftではこのようなミスを防ぐため、代入=
を使った場合はエラーとして処理されます。この修正は、Swiftが登場した当初からの大きな売りの1つでした。
また、コーディング中にエラーメッセージが表示されたとき、そのメッセージが非常に直感的であるという点も興味深いです。このようなエラーメッセージを通して、言語の設計者の意図やユーザーの使いやすさへの配慮を感じることができます。
そのため、Swiftではこういったエラーが出た際には、正しい方法に導く機能も備えられているというのが大きなメリットです。これは言語の進化の一つと言えるでしょう。 Swiftでは、リターンが便利である一方で、うっかりすると危険を伴うことがあります。特に、バグが見つけにくいことが問題です。Swiftはこのような過去の問題を参考にして、安全性を確保するために特定の戻り値やイコールの使用を制限しています。たとえば、if文ではブール型しか使用できないため、不適切な型が使用されないようになっています。
イコール演算子については、Swiftの標準ライブラリでは定義されていないため、詳細を見ることができるのはオープンソースのSwiftプロジェクトです。ただし、こうした標準ライブラリにない機能の詳細を深く掘り下げることはあまりしません。プラスイコール(+=)
のような演算子も、右辺を左辺に加えるだけで戻り値を持たないため、意図しない使用を防ぐ効果があります。
関数の戻り値を返さないことについても、一般的に誤用を防ぐための対策です。この「戻り値がない」という表現について言うと、実際にはSwiftで戻り値がない関数を定義する際、省略されていてもVoid
型が返されるという仕様です。この点で、戻り値を返さないという表現には注意が必要です。
Void
型は空のタプルとして扱われ、実際には存在するが何も値を持っていない状態を表します。これによって、次の処理に進むための最低限のリターンがされていることになります。本当に戻り値がない状態を示すには、Never
型を使用します。Never
型は戻り値を返すことができず、そのためにその後のプログラムが続行できないことを明示します。これが重要な概念であり、プログラミングの安全性を考える上で認識しておくべき点です。 演算子に関して、いくつかの定義がありますが、重要な点として「Never」の場合について説明します。「Never」という列挙型はケースがないという意味で定義されています。通常の列挙型、例えば以下のように定義されたものです:
enum Value {
case x
case y
}
この場合、「x」や「y」といった値を表せますが、「Never」型になるとこれらの値が一切存在しなくなります。つまり、究極的に値がないということを表現するための型です。
代入演算子は戻り値を返さないと言われますが、実際には空のタプル(Void
)を返しています。これを理解するために、代入演算子の動作を見てみましょう。
例えば、次のようなコードがあります:
var x = 10
print(x)
x = 20
print(x)
このコードは正常に動作し、期待通りに出力されます。ここで、Optional
型を使う場合の例を考えてみましょう:
var y: Int? = 10
if let unwrappedY = y {
print(unwrappedY)
}
y = 20
print(y)
この場合、Optional
型の性質上、代入ができるわけです。ですので、Optional
に代入する際には、通常の代入と変わらない動きをします。
ただし、代入演算子の戻り値はVoid
を返すという特徴があります。これは次のように確認できます:
let result = (x = 20)
print(result) // ()
この例では、代入演算子の結果としてVoid
型の値が返されます。ここを理解すると、演算子に対する注意点が分かりやすくなります。
また、例えばx += 10
のような累算代入演算子について考えてみると、Optional
型ではこのような演算は直接できない場合があります。Optional
型には特定の操作をサポートしていないため、この種の操作には工夫が必要です。
さらに、Optional
を使った代入などについて扱うにあたって、例えばValue
型というバリュー型を考えます。以下のコードを示します:
struct Value {
var x: Int = 0
}
var valueInstance: Value? = Value()
valueInstance?.x = 5
この例では、Optional
型の変数に対して値の代入を行おうとしています。もしvalueInstance
がnil
だった場合、代入や操作は行われませんが、Optional
型の安全性が確保されている形になります。Optional
の取り扱いには、その特異性を把握した形でのアプローチが重要です。
このように、Swiftでは演算子や代入の仕組みについて、Never
やVoid
型と組み合わせながら柔軟に扱う必要があります。いろいろ試行錯誤する中で、それぞれの型が持つ特性を活かしたプログラミングが求められるのです。 代入式が正しく実行されたか確認する際、Swiftではイコール演算子が元々ボイドを返すため、オプショナルチェーニングを使うと、その結果としてボイドのオプショナル型になります。これには重要な特徴があります。式が実行された場合は「何か」があり、されなければ「何もない」といった判別がボイドがリターンされることによって可能になります。
イコール演算子が拒否されたということを先ほど言ったかもしれませんが、実際にはこれはプラスイコールの場合に少し形が変わることがあるようです。ただし、強制アンラップが必要かどうかについては再考が必要です。丸括弧を使えば何かしらの効果があるのではないかと期待するかもしれませんが、長石してくれるわけではありません。オプショナルタイプ、つまりボイドのオプショナルについて知っておくと、if文などで「ニルでない場合」の判断に使えることを思い出しました。
この特性を利用すると、ボイドだからこそオプショナルに情報を保持でき、実行方法を判定できるという利点があります。普段は滅多に使うことはないですが、ボイドが返ることは重要です。スライドで「ボイドを返さないこと」と書かれていたことに少し驚きましたが、通常はボイドを返すことで安全性が高まるという特徴があります。
今回はここまでにして、次回は3月演算子のオーバーフローに関して見ていこうと思います。今日はこれで終わりにします。お疲れ様でした。ありがとうございました。