Swiftの基本型

プログラミングで扱うデータには型が決められており、扱いたいデータや実現したい操作によって適切な型を使用する必要があります。
今回はSwiftで使われている型についてまとめていきたいと思います。

型とは

「3」は数値を表し四則演算などの計算が可能ですが、「あ」は文字を表しており数値のように四則演算を行うことはできません。
この、「3」は「数値」(特性)であり「四則演算が可能」(操作)といった、扱う値による特性と値への可能な操作を表したものが型です。
私たちは普段、”123″や”abc”といった文字を見た際に、特に意識することなく数字や文字列を表していると捉えています。
そのため、”123 + abc”や”123 ÷ abc”という演算操作は”abc”が文字列であるため不可能である、と考えるまでもなくわかりますよね。
コンピュータ上でも上記のような値の種類による操作を適切に行えるように、プログラミング言語では数値の型や文字列の型などが用意されており、値を適切に操作できるようになっているのです。

基本型の種類

では、実際にSwiftで用意されている型の種類とその特性・操作を見ていきます。
Swiftで用意されている基本型は以下のとおりです。

型名特性操作
Bool型真理値論理演算、分岐の条件式
String型文字列文字列の操作(比較、結合、検索など)
Int型整数整数同士の四則演算、比較演算
Float型浮動小数点四則演算、比較演算
Double型浮動小数点四則演算、比較演算

次の章からそれぞれの型について詳しく見ていきます。

Bool型

Bool型とは?

Bool型とは、真(True)と偽(False)の二つの値を持つ真理値を表す型です。
条件分岐などはBool型を用いて判定します。
例えば、「点数が80点以上の場合、合格とする」のような分岐をしたい場合、「点数が80点以上」であれば真となり、「点数が80点未満」であれば偽になり、このBool値を元に条件分岐の処理を記述していくのです。

論理演算

論理演算とは、真理値に対して行う演算です。
Bool型は真理値を表す型なので、論理演算を行うための演算子が用意されています。
論理演算子は否定(NOT)、論理積(AND)、論理和(OR)の3種類あります。
それぞれ詳しく見ていきましょう。

否定(NOT)

否定(NOT)は真理値の真偽を逆にします。
!演算子を用いることで否定を求めることができます。

let a = true // true
let b = !a // a(true)の否定のためfalseになる

論理積(AND)

論理積(AND)は与えられた複数の真偽値が全て真だった場合は真となり、それ以外は偽となる論理演算子です。
&&演算子を用いることで論理積を求めることができます。

let a = true && true // true
let b = true && false // false
let c = false && true // false
let d = false && false // false

論理和(OR)

論理(OR)は与えられた複数の真偽値のうち、一つでも真があれば真となり、全て偽の場合のみ偽となる論理演算子です。
||演算子を用いることで論理和を求めることができます。

let a = true || true // true
let b = true || false // true
let c = false || true // true
let d = false || false // false

論理演算子の優先順位

論理演算子には、算術演算子で乗除の計算を加減より先に行うような、優先順位があります。
論理演算子の優先順位は、否定→論理積→論理和の順になっています。
優先順位を任意に変更したい場合は、算術演算子と同様に()で囲むことでできます。

let a = true
let b = false
let c = !a && b || a // true
// 「!a = false」 → 「false(!a) && b = false」 → 「false(!a && b) || a」 → true となる
let d = !(a && (b || a)) // false
// 「b || a = true」 → 「a && false(b || a) = true」 → 「!true(a && (b || a))」 → false となる

String型

String型とは?

String型とは文字列を表す型です。
Unicodeで定義された任意の文字列を扱うことができます。
リテラルで文字列を表す場合、"abc"のようにダブルクオーテーションで囲むことで表すことができます。

let a = "abcdef" // String型を表す
let b = "123" // 数値型ではなくString型となる

文字列リテラルの操作

文字列リテラルを扱う際はダブルクオーテーションで囲むことで表すと前述しましたが、文字列リテラルには他にも様々な操作があります。

エスケープシーケンス

エスケープシーケンスとは文字列内で特殊文字を表したい場合に用いる表現方法です。
文字列リテラル内に"や改行などの特殊文字を含めたい場合、そのまま表記することはできません。
そこで用いるのがエスケープシーケンスになります。
Swiftのエスケープシーケンスでは、\(バックスラッシュ)から始まる文字を特殊文字として扱います。
主な特殊文字の表現方法は以下の通りです。

\nラインフィード(改行)
\rキャリッジターン(改行)
\”ダブルクオーテーション
\’シングルクオーテーション
\\バックスラッシュ
\0null文字

実際にエスケープシーケンスを用いてダブルクオーテーションと改行を利用すると以下のようになります。
画像の下の部分が出力結果になるのですが、ダブルクオーテーションで文字が囲まれ、改行がされているのがわかると思います。

文字列リテラル内での展開

エスケープシーケンスの\()を用いることで、値を文字列リテラル内で展開することができます。
この記法では()内の式の評価結果を文字列リテラルに埋め込むことができます。

let a = "sum: \(3 + 5)"
print(a) // sum: 8

let win = "勝ち"
let str = "result: \(win)"
print(str) // result: 勝ち

文字列の比較

String型は==演算子を利用することで内容を比較し、同じかどうかを判定することができます。
また、!=演算子を利用することで内容が異なるかどうかを判定することができます。

let str1 = "abc"
let str2 = "def"
let str3 = "abc"

str1 == str2 // false
str1 == str3 // true
str1 != str2 // true
str1 != str3 // false

文字列の結合

String型は+演算子を利用することで文字列同士を結合することができます。

let str1 = "abc"
let str2 = "def"
let str3 = str1 + str2 // "abcdef"

Int型

Int型とは?

数値型は上記の表で見たように、整数と小数で型が分かれています。
Int型とは、そのうちの整数を表す型になります。
ダブルクオーテーションなどで囲まずにそのまま整数を記述するとInt型となります。

let int = 123 // Int型となる。小数などの他の数値型にはならない。

その他の整数型

Int型が一般的に利用される整数型となりますが、それ以外にも何ビットのデータかによって型が分けられています。
ビット数は割り当てられるメモリ領域の大きさを表しており、ビット数が大きいほど表現できる数値の幅が広がりますが、多くのメモリ領域を使うことになります。
通常のInt型は32ビットのプラットフォームであれば32ビット、64ビットのプラットフォームでは64ビットとなります。
Int型以外の固定ビット数の整数型、及びそれぞれの最大値・最小値は以下の通りです。

型名ビット数最小値最大値
Int88-128127
Int1616-32,76832,767
Int3232-2,147,483,6482,147,483,647
Int6464-9,223,372,036,854,775,8089,223,372,036,854,775,807

最小値・最大値は、nビットのデータ領域では2のn乗通りのデータ表現を正負で分けた数値となります。正の数が1少ないのは0があるためです。
例えば、8ビットの場合は2の8乗=256通りの表現ができるため、最小値は256の半分の-128、最大値は256の半分から0を抜いた127となります。
整数型のビット数は普通に開発する上では意識することは少ないですが、パフォーマンスを少しでも上げるために必要最小限の固定ビット数値型を定義する場合や、32ビットプラットフォームで32ビットで表現できる約21億以上の大きな数値を扱う場合などは意識する必要があります。

Double型

Double型とは?

Double型とは小数を表す型です。
Double型の小数は浮動小数点という方式で表現されています。
小数をそのまま記述した場合、このDouble型として扱われます。

let num = 1.1 // Double型となる。

Double型は64ビットの固定ビット数を持ち、およそ10の308乗の正負の値まで表現することができます。

Float型

Float型とは?

Float型とは、Double型と同様に浮動小数点方式で表現された小数を表す型です。
Double型との違いは、固定ビット数とビット数の違いによる表現できる数値の幅と精度です。
Float型は32ビットの固定ビット数を持ち、およそ10の38乗の正負の数まで表現できます。
Double型よりも表現できる数値の幅が狭く、精度は低いですが利用するデータ領域は小さいです。

let num: Float = 1.1 // Float型の変数に代入し利用する

数値型の演算

算術演算

数値型では加減乗除の算術演算を行うことができます。
また、数値型の演算は同じ型同士でないと行えません。
つまり、同じ整数型でもInt8型とInt型を演算することはできませんし、浮動小数点型であるDouble型とFloat型も演算することはできません。
算術演算子の種類は以下の通りです。

+加算
減算
*乗算
/徐算
%徐算した余り

実際の利用例は以下の通りです。

let a = 5 + 2 // 7
let b = 5 - 2 // 3
let c = 5 * 2 // 10
let d = 5 / 2 // 2
let e = 5 % 2 // 1

let int = 1
let double = 1.1
let sum = int + double // コンパイルエラーとなる

比較演算

数値型で行えるもう一つの演算として比較演算があります。
比較演算では数値が等しいか、等しくないか、大小の比較などを行いBool型の値を返却します。
また、比較演算でも算術演算と同様に同じ型同士でないと演算が行えないようになっています。
比較演算子の種類は以下の通りです。

比較演算子演算内容
==左辺と右辺が等しい
!=左辺と右辺が等しくない
>=左辺が右辺以上
>左辺が右辺より大きい
<=左辺が右辺以下
<左辺が右辺未満

実際の利用例は以下の通りです。

3 == 4 // false
3 == 3 // true

3 != 4 // true
3 != 3 // false

3 >= 4 // false
3 >= 3 // true
3 >= 2 // true

3 > 4 // false
3 > 3 // false
3 > 2 // true

3 <= 4 // true
3 <= 3 // true
3 <= 2 // false

3 < 4 // true
3 < 3 // false
3 < 2 // false 

型の変換

プログラムでは扱うデータの特性によって適切な型を利用するということをまとめてきました。
今まで見てきたように型によってできる処理は決まっているため、Int型の値を文字列として扱いたい時や、Int型の値とDouble型の値で演算を行いたい場合は型の変換を行う必要があります。
この章では、その型の変換についてまとめていきたいと思います。

イニシャライザ

型の変換はイニシャライザを利用して行います。
イニシャライザは型名(変換する値)で呼び出すことができます。

let num1 = 123 // Int型
let str: String = String(num) // String型のイニシャライザでnumをString型に変換

let strNum = "456" // "456"という文字列を表すString型
let num2 = Int(strNum) // Int型のイニシャライザでstrNumをInt型に変換

let double = 1.1
let sum = Double(num1) + double // Double型のイニシャライザでnum1をDouble型に変換し演算

他のプログラミング言語などには暗黙の型変換という機能が付いているものもあります。
暗黙の型変換とは、例えば整数型と小数型の演算の際に、明示的に型変換を行わなくてもプログラムの方で判断して型変換を行なってくれる仕組みのことです。この例えの場合はより精度の高い小数型に合わせて整数型が暗黙的に小数型に変換されます。
しかし、Swiftにはそのような機能はなく違う型で演算を行うとコンパイルエラーとなります。
暗黙的な型変換は記述量が減りシンプルにコードを書けるというメリットがありますが、数値の切り捨てなどで思わぬバグが生まれる可能性が高いというデメリットもあります。
Swiftでは明示的に型変換を行う必要があるため、型変換を意識せざるを得なくなり、より安全なコードを書くことができる可能性が高くなっています。

型変換時の注意点

型の変換を行う際、変換する型同士の精度の差を意識する必要があります。
例えば、数値から文字列に変換する場合は特に何も意識する必要はないですが、文字列から数値に変換する場合、変換する文字列は数値に変換可能な値である必要があります。
また、数値型同士の変換でもより精度の高い型への変換は問題ないですが、より精度が低い型への変換を行う場合は桁の喪失などを意識しなければなりません。

let int = 123
let intToStr = String(int) // "123" Int型からString型への変換は問題ない

let str1 = "456"
let str1ToInt = Int(str1) // 456 String型からInt型への変換の場合、数値に変換可能である必要がある

let str2 = "abc"
let str2ToInt = Int(str2) // nil Int型への変換が失敗すると何もない値を表すnilとなる

let intToDouble = Double(int) // 123 Int型からDouble型の変換は小数の方が精度が高いので問題ない

let double = 1.1
let doubleToInt = Int(double) // 1 Double型からInt型への変換は小数点以下の桁を喪失する

Any型

最後に任意の型を表すAny型について説明します。
Any型の変数や定数はどのような型の値も代入することができるため、型が定っていない場合に利用します。
Any型の利用をする際は値を生成するのではなく、他の型の値をAny型の変数や定数に代入するなどしてAny型として扱います。

var anyVar: Any

// Any型の値は任意の型の値を代入することができる
anyVar = "abc"
print(anyVar) // ”abc"

anyVar = 123
print(anyVar) // 123

Any型は任意の型を扱うことができるという利点がありますが、それぞれの型で利用可能だった特有の操作ができなくなるという欠点があります。
例えば、Int型の四則演算やBool型の論理演算などができなくなります。

let intA: Any = 1
let intB: Any = 2

print(intA + intB) // コンパイルエラー

let boolA: Any = true
let boolB: Any = false
print(boolA && boolB) // コンパイルエラー

上記の欠点があることから、Any型への代入はなるべく避け、型をしっかり定義することが望ましいでしょう。

まとめ

今回は基本型についてまとめました。
プログラミングを学ぶ上で基礎的かつ重要な概念である型ですが、しっかりと学べばそこまで難しいものではないと思います。
Swiftは静的型付けで暗黙的な型変換はできないため、コーディングをしていく際に型を強く意識できるように設計されており、安全なコードを書きやすい設計になっているのだと感じました。
最後まで読んでいただきありがとうございました。
それでは、また。