2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【カタカナ禁止で】初心者のためのSwiftの"?"と"!"

Last updated at Posted at 2023-02-12

はじめに

プログラミングにはカタカナ語が多すぎる!!!!!


Swiftをやってて、これらのエラーに当たったことはありませんか?

  • Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
  • Coalesce using '??' to provide a default when the optional value contains 'nil'
  • Force-unwrap using '!' to abort execution if the optional value contains 'nil'

で、どういう意味かと思って調べてみたものの、「オプショナル」だとか「アンラップ」だとかのカタカナ語を前にして挫けたことありません?
それで結局、よく分からずにFixを押して、「なんでか知らんけどエラー消えたしいいや」ってなってませんか?

この記事を頑張って読めば、これらのエラーの原因がちゃんと分かるようになります。

注意書き

  • ?!の基礎だけを簡単に理解できるようにしたために、紹介しきれなかった概念などが少しあります。

  • この記事は、以下の内容を分かっている前提で話を進めていきます。

    • 変数や型について(IntStringなど)
    • if文などの基礎的な文法
  • 「カタカナ禁止」を謳ってはいますが、「エラー」などの最低限のカタカナ語は使います。お許しを…。

まずは前提知識から

空っぽ(nil)という概念

冒頭のエラーについて理解するには、まず初めにnilという概念について理解する必要があります。

nilというのは、変数の中が空っぽだよ、何も入ってないよということを表す概念です。

少し強引ですが、「nilについてよう分からん」ってなったら、とりあえず頭の中でnilを「空っぽ」と読んでください。だいたい合っているはずです。


★重要★ nilは「空っぽ」を表す。


nilの使いどころ

例えば、会員登録の際のデータとして、任意で年齢を知りたいという場合について考えてみます。(「任意で」というのがとても重要です。)

年齢は間違いなく整数ですから、データはInt型の変数で持っておけば良さそうですね。

ところが、「任意で知りたい」というのが厄介です。
年齢の入力が任意ということは、「年齢の欄に何も入力されない」という場合も考えられるわけです。

そこで、年齢の欄に何も入力されていなければ、変数の中身を、「空っぽ」であることを表すnilにしておきます。
こうすることで、「年齢が入力されなかった」ということを、nilによって知ることができるのです。

「普通の変数」も見ておこう

実際にプログラムでnilを使う手順について説明する前に、まずは前提知識として、皆さんがいつものように使っている「普通の変数」について考えてみます。

Swiftにおいて、「普通の変数」には必ず何かしらの「値」が入っていなければなりません。
(ここで言う「値」というのは、例えばString型の変数では何かしらの文字列、Int型の変数では何かしらの数字…などといった具合です。)

つまり、Swiftの「普通の変数」において、「変数の中身が空っぽ」というようなことは想定されていないのです。
そのため、Swiftでnilを扱うには、その変数を宣言するときに、「普通の変数」を使うときとは違うことをしなければなりません。

nilを代入できる変数を使う

変数にnilを代入するには、型の名前の後ろに?をつけます

例1:nilを代入できる変数の宣言
let hoge: Int = 0 //空っぽ(nil)を代入できない🙅‍♂️
let fuga: Int? = nil //空っぽ(nil)を代入できる🙆‍♂️

上の「例1」では、fuga:の後ろのIntにくっついている?がそれです。
?をつけることで、「nilも代入できる」ということが分かりやすくなりますね。

ちなみに!
変数名になっているhogefugaというのは、「何でも良い、特別な意味のない名前」で、よくサンプルのプログラムなどで使われているものです。
このような「意味のない名前」のことを、難しい用語で「メタ構文変数」と呼びます。


★重要★ ?をつければ、変数にnilを代入できる。


実際にnilを使うときの注意点

ここからは、nilを代入できる🙆‍♂️ 変数を使うときの注意点について話します。

なぜ?をつけて区別するの?

みなさん、疑問に思いませんか?

なんでわざわざ?をつけて普通の変数と区別するの?
普通の変数に直接nilを代入しちゃえば良くない?

↓こんな感じで↓

例2:こんな感じで書いちゃえば良くない?
let hoge: Int = nil //?をつけていないのにnilを代入しているので、もちろんエラー❌

では、なぜ「例2」のように書けないのでしょう?

答えは、nilも代入できる」というのがなかなか厄介だからです。

nilの厄介な一面

その厄介な点というのは、プログラムの中でnilを直接扱うと、エラーとなり、アプリが落ちてしまうことです。

nilを代入できる🙆‍♂️ 変数には、常に「もしかしたら中身がnilかもしれない」という可能性があります。
そのような、「もしかしたら中身がnilかもしれない変数」をプログラムでそのまま使ってしまうと、実際に中身がnilだった場合にエラーとなり、アプリが落ちてしまいます。

使っているアプリが突然落ちるなんて、勘弁してほしいですよね。

nilによるエラー」を防ぐための取り組み

そのようなnilによるエラーを防ぐために、Swiftでは
1. nilを代入できない🙅‍♂️ 変数
2. nilを代入できる🙆‍♂️ 変数
の2つを同じように扱えないようになっています。

↓具体的にはこんな感じ↓

例3:nilを代入できない🙅‍♂️変数 と nilを代入できる🙆‍♂️変数 を同じように扱ってしまう例
let hoge: Int = 0 //nilを代入できない🙅‍♂️
let fuga: Int? = 1 //nilを代入できる🙆‍♂️

print(hoge + fuga) //nilを代入できない🙅‍♂️ と nilを代入できる🙆‍♂️ を同じように扱ったのでエラー❌

「例3」で、hogeIntとなっているので nilを代入できない🙅‍♂️ 変数fugaInt?のように?がついているので nilを代入できる🙆‍♂️ 変数です。
print(hoge + fuga)のところでは、nilを代入できない🙅‍♂️ 変数nilを代入できる🙆‍♂️ 変数同じように扱ってしまっているため、エラーになってしまっているのです。


★重要★ IntInt?は同じように扱えない。


nilにまつわる「型」の話

では、nilを代入できない🙅‍♂️ 変数nilを代入できる🙆‍♂️ 変数のどこが違うために、同じように扱えないのでしょう?

実は、これら2つの変数の違いには「型」が関係しています。
(ここで言う「型」は、String型やInt型と言うときの「型」と同じようなものだと考えてください。)

このことについて、先ほどの「例3」の事例で説明すると、Intとなっているhogeと、Int?となっているfugaが、同じように見えて実は違う「型」だということです。

ここでひとつ、考えてみてほしいんですが、下の「例4」のように、String型の変数とInt型の変数をまぜこぜにして扱えませんよね。

例4:これがエラーになるのと同じこと
print("こんにちは" + 3) //String + Intは計算できないのでエラー❌

これと同じように、nilを代入できない🙅‍♂️ 変数nilを代入できる🙆‍♂️ 変数においても、そもそも型が違うのでまぜこぜにして扱えないのです。

ちなみに!
Int?のような「?付きの型」には、「オプショナル型」という名前がついています。


★重要★ IntInt?は違う「型」


型をそろえる / ?を取る

つまり、「例3」のような計算をするためには、まず「Int?Intに変換して、型をそろえる作業」が必要なのです。
これもう少し簡単に言うと、?を取る作業」 となります。

「例3」では、この作業をしなかったのでエラーになったというわけです。


★重要★ nilを代入できる🙆‍♂️ 変数を使う前に、「?を取る作業」が必要


?の取り方3選

以下では、「?を取る3つの代表的な方法」について、順番に見ていきます。

ひとつめ: !

一つ目は!です。これは簡単に使えますが、力技です。

!の使い方

nilを代入できる🙆‍♂️ 変数の後ろに!をつけます。

この!によって、変数の中身に関わらず強制的に?が取れます。
(「強制的に」というのがとても重要です。)

例5:fugaが1の場合
let hoge: Int = 0
let fuga: Int? = 1

print(hoge + fuga!) //fugaの"?"を取って計算している。結果は1⭕️

しかし、はじめに力技と言った通り、この方法は万能ではありません

下の「例5」のように、fugaの中身がnilの場合、!を使うとエラーとなってアプリが落ちてしまいます。

例6:fugaがnilの場合
let hoge: Int = 0
let fuga: Int? = nil //例4と例5では、ここが"1"から"nil"に変わった

print(hoge + fuga!) //nilに対して"!"を使えない。よってエラーとなる❌

そのため、この方法は、変数の中身が確実にnilではないと分かっているときしか使えません。

ふたつめ: ??

二つ目は??です。これも、簡単に使えます。

??の使い方

nilを代入できる🙆‍♂️ 変数の後ろに??をつけ、さらにその後ろに、nilだった場合に代わりに使う値を書きます。

こうすることで、変数の中身がnilだった場合に、その代わりとして??の後ろの値が使われます

例7:hogeが1の場合
let hoge: Int? = 1

print(hoge ?? 0) //hogeがnilではないので、hogeの値がそのまま出力される。結果は1⭕️
例8:hogeがnilの場合
let hoge: Int? = nil

print(hoge ?? 0) //hogeがnilなので、??の後ろの値が出力される。結果は0⭕️

??を使う場合、中身がnilだった場合の「身代わり」となる値が後ろに用意されています。
そのため、!を使ったときのように、エラーとなってアプリが落ちることがありません。

つまり、、??を使う方が、を使うよりも安全にnilを扱うことができます

みっつめ: if let

三つ目はif letです。
こちらは少し難しいですが、理解さえすればnilを扱うときの幅が大きく広がります。

if letの使い方

新たに用意した変数に nilを代入できる🙆‍♂️ 変数を入れてみて、その中身がnilじゃない場合にのみif文の処理を行います。

逆に、もし変数の中身がnilだった場合、if文の処理は行われません

例9:基本の使い方
let hoge: Int? = 1

if let fuga = hoge { //とりあえずfugaにhogeを代入 → 中身がnilじゃなかったらif文の処理を行う
    print(fuga)
    print("nilじゃなかったよ😊")
}
//結果⭕️
//1
//nilじゃなかったたよ😊

また、elseを追加することで、変数の中身がnilだった場合に行うべき処理も書けます。

例10:elseで中身がnilの場合の処理を追加
let hoge: Int? = nil

if let fuga = hoge {
    //ここは中身がnilじゃない場合に実行される (この例では、hogeの中身がnilなので実行されない)
    print(fuga)
    print("nilじゃなかったよ😊")
} else {
    //ここは中身がnilだった場合に実行される
    print("nilやんけ😡")
}
//結果⭕️
//nilやんけ😡

このように、if letでは、変数の中身がnilでない場合にのみ行うべき処理を書くことができます。
また、変数の中身がnilだった場合とそうでない場合で、行うべき処理を明確に分けられる点も、if letの特徴だということができます。

ちなみに!
これまでに3つ見てきた「?を取る作業」には、「アンラップ」という名前がついています。

まとめ

  • nilは「空っぽ」を表す。
  • 型の名前の後ろに?をつければ、変数にnilを代入できる。
  • IntInt?は違う「型」
  • nilを代入できる🙆‍♂️ 変数を使う前に、「?を取る作業」が必要

おわりに

この記事は、初心者の理解のとっかかりになればと考えて書きました。
そのため、「guard let」や「オプショナルバインディング」など、説明を省いた概念や用語があります。

もし「もっと学びを深めたい」ということでしたら、下の記事を読むのが良いと思います。
この記事では説明できなかった概念や用語なども含めて、とても分かりやすく説明されています。

最後に、誤字や脱字があったり、内容が誤っていたりしたら教えていただけると嬉しいです。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?