【プログラミング初心者】Swift基礎~変数・型~

プログラミング初心者、初級者に向けてSwiftをベースとした変数宣言、型の種類について紹介していきます。

## 変数
プログラミングでは処理をする際様々なデータを扱います。
このデータはコンピュータの記憶領域(メモリ)に保存されます。
プログラミングではこのメモリに**変数**名前を付け、変数経由でメモリの読み書きをします。

変数を扱う前には「今からこんな名前の変数を使います」とコンピュータに教えてあげる必要になります。
これを変数を**宣言**するとか**定義**するとか言ったりします。
以下の例は`x`という名前の変数をInt型で宣言しています。(※型については後述)

```swift
var integer: Int
```
宣言した後は`integer`という名前でメモリにアクセスすることができます。
`integer`という名前の箱をメモリに準備し、その中のデータを参照したり更新するというようなイメージです。

### 変数・定数
先述した説明ではデータの扱いはまとめて変数といってますが実際には変数と**定数**があります。
それほど違いはなくイメージのまま変数は読み書き可能で、定数の場合書き込みは初期化の時のみでその後はデータの更新はできません。
宣言の仕方が変数と定数では少し異なり、変数の場合は`var`、定数の場合は`let`をそれぞれ宣言時に付けます。

```swift
var variable: Int = 0
variable = 10 // 変数は書き換え可能

let constant: Int = 0
constant = 10 // 定数は読み込みのみなのでエラー
```

書き換えの必要がないものには`let`を使ってあげましょう。

## 型について
変数を扱う際は型というものを意識します。
型とは扱う変数がどんな種類でどんな性質を持っているのかなど、そのデータの特性を表すものです。
代表的なものとしては文字列を扱うString型、整数を扱うInt型などが挙げられます。

変数は指定された型しか扱えません。
例えばInt型で宣言した変数に文字列を格納しようとしてもプログラムは理解できずエラーとなります。

```swift
var integer: Int = 0
integer = "文字列を代入" // 型が異なるためエラー
```
(補足ですが文字列は`"~"`で表されます)

このように明確に型を付けてあげることを**型アノテーション**といいます。

もし型というものがなければ、例えば金額の計算をしていたのにいつの間にか「ああああ１１１」という結果になってしまうということもありえます。
そうなるとアプリが実装者の意図した挙動をしない可能性が出てきます。それを未然に防ぐためにSwift自体がエラーを出してくれます。

余談ですがSwiftなどはコンパイラ言語と呼ばれ型宣言を必要としています。一方でスクリプト言語と呼ばれるJavaScriptやPHPなどでは型がありません。
そのためスクリプト言語ではいつの間にか変数が文字列に変わっていたということは発生したりします。これは実装者がそうならないように気をつけて実装していく必要があります。

## メモリアドレス
少し変数宣言について内部処理の話をします。少し難しいかもしれないので、理解できなければそんな感じなのかーくらいの認識を持つ程度で大丈夫です。
そこまで気にしなくてもSwiftはとりあえずは書けます。

実際、変数には**アドレス**と呼ばれるメモリの場所、住所が記録されています。
メモリはコンピュータから1bitに対し1アドレスが割り当てられています。(1byte毎かもしれません。。)
アドレスは整数で定義されており[16進数](https://wa3.i-3-i.info/word1610.html)で表されることが多いです。
そしてメモリ１つ１つに対して0 or 1のデータが格納されています。
<img width="578" alt="メモリ１.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/e0d7be3f-baf7-b07f-a467-0e1e7a2834da.png">

変数は扱うデータを表すメモリ領域の先頭のアドレスを持ちます。
先頭アドレスがわかればどこにデータの内容が確保されているかわかります。
では先頭はわかりましたがこの変数はどのメモリまでをデータとして扱えばいいのでしょうか？
それを表すのが型です。
型にはそれぞれ必要とする長さが決まっています。
(全部がそうではありませんがそういったイメージでいいです)
環境によって変わったりしますがIntなら64bitを確保します。
<img width="584" alt="メモリ２.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/c8d515a9-5ab5-a786-c8ce-488b302071c7.png">

このようにしてどこからどこまでを１つのデータとして扱うかを決めています。
結局扱う際はこのデータのまとまりを１データとして扱うためIntとして大きな箱がメモリに準備されると思ってもらえれば問題ありません。

## 型推論
さて、ここまで変数には型が必要だと説明してきましたが、実はSwiftでは実装者が型アノテーションで明確に型を宣言しなくても良い場合があります。むしろそのパターンの方が多かったりします。
この機能を**型推論**といい、読んで字のごとく型を推測してくれます。

例えばIntの場合以下のように定義することができます。

```swift
let integer = 0
```
このように宣言した場合、Swiftの方で勝手にこれは整数を扱っているから`Int`型だなというように推測してくれ、その後はInt型として扱うことができます。

型推論とはいえSwift側では型を明確にできるためIntと推論されたものに対しては文字列は代入できません。

```swift
var integer = 0
integer = "文字列を代入する" // Swift側でエラーとして扱ってくれる
```
このようにSwift側でエラーを表示してくれるため型の違いによる意図しない挙動は起こらないようになっています。

一方で型アノテーションをしてあげないといけない型もあります。
例えば使うことは少ないですが`Int32`型などです。`Int32`型は`Int`型と違い32bit分の整数しか扱わない型です。
同じ整数型ですが`var integer = 0`と宣言するとSwiftは`Int`と認識するため
明示的に`var integer: Int32 = 0`としてあげる必要があります。

特に明確に型を区分する場合は以外は型推論を使ってあげればいいかと思います。

## 基本型一覧
本項ではSwiftの基本となる型を紹介します。

### 整数
整数データを扱う型です。
基本的には`Int`型を使います。
Int型は型アノテーションを必要としません。

整数型には符号ありと符号なしがあります。符号なしは負の数「-」は扱わないという意味です。
それぞれの型で扱える値の範囲が違います

- 符号あり
 - Int,Int8,Int16,Int32,Int64
- 符号なし
 - UInt,UInt8,UInt16,UInt32,UInt64 

```swift
let integer: Int = 10        // 32bit環境ではInt32、64bit環境ではInt64と同じ
let integer8: Int8 = 10      // -128〜127
let integer16: Int16 = 10    // -32768〜32767
let integer32: Int32 = 10    // -2147483648〜2147483647
let integer64: Int64 = 10    // -9223372036854775808〜9223372036854775807
let uInteger: UInt = 10      // 32bit環境ではUInt32、64bit環境ではUInt64と同じ
let uInteger8: UInt8 = 10    // 0〜255
let uInteger16: UInt16 = 10  // 0〜65535
let uInteger32: UInt32 = 10  // 0〜4294967295
let uInteger64: UInt64 = 10  // 0〜18446744073709551615
```

### 少数
主に`Double`型と`Float`型があります。
それぞれ内部での数値の持ち方が異なり、Doubleの方が正確です。
基本的には`Double`を使用します。
型アノテーションなしの場合は`Double`型になります。

```swift
let double: Double = 0.1    // 64bit
let float: Float = 0.1      // 32bit
let float32: Float32 = 0.1  // 32bit
let float64: Float64 = 0.1  // 64bit
let cgFloat: CGFloat = 0.1  // 32bit環境ではFloat32、64bit環境ではFloat64と同じ。UI周りでよく使われている
```

### 文字列
`String`型のみと思っていいです。
型アノテーションなしで使用できます。

```swift
let string: String = "文字列"
```

### 論理型
`Bool`型。真偽値を扱います。
値はtrue/falseのみです。
型アノテーションなしで使用できます。

主に条件判定の際に使います。

```swift
var boolean: Bool = true
var equalBoolean = 0 == 0
```

### 配列
「配列」とは複数の値を格納するための型です。
画像を見たほうが想像が付きやすいと思います。
<img width="502" alt="配列.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/5d093614-4924-5412-d3b4-c099cfb7d1ed.png">

少し注意が必要なのは配列の最初が**０番目**から始まることです。
数学の数列などでは１番目から扱うことが多いですがそこは異なっています。

配列は`Array`型ですが、宣言の仕方が少し特殊です。

配列には変数を格納していくため、その変数自体の型情報も一緒に定義してあげる必要があります。
宣言した型以外のものを入れるとSwiftからエラーが表示されます。
宣言の構文は`var 名前: [型] = 初期値`です。

```swift
var integerArray: [Int] = [0, 1, 5, 19]                 // Intを格納する配列
var stringArray: [String] = ["りんご", "みかん", "バナナ"]  // Stringを格納する配列
```

`配列名[n]`で格納した値にアクセスすることができます。

```swift
// 参照
print(integerArray[0]) // 0
print(stringArray[2]) // バナナ

// 更新
stringArray[0] = "パイナップル"
print(stringArray[0]) // パイナップル
```

また初期値は空でもよく、さらに変数として宣言している場合後から追加、削除できます。
追加は`配列名.append(追加する要素)`
削除は`配列名.remove(at: 削除する要素の配列番号)`
※`append`は配列の一番後ろに要素を追加します。他にも間に挿入するなどもあります。

```swift
// 配列の初期値を空で宣言
var stringArray: [String] = []
// 追加処理
stringArray.append("りんご")
stringArray.append("みかん")
print(stringArray) // ["りんご", "みかん"]

// 削除処理
stringArray.remove(at: 0)
print(stringArray) // ["みかん"]
```

補足として配列を定数として宣言した場合、更新はできません。
`append`や`remove`も同様に使えません。

```swift
let constantArray: [String] = ["りんご", "みかん"]

// 更新できない
constantArray[0] = "パイナップル" //エラー
constantArray.append("メロン") // エラー
constantArray.remove(at: 0) // エラー

// 参照はできる
print(constantArray) // ["りんご", "みかん"]
print(constantArray[0]) // "りんご"
```

また、配列は初期値が空でない場合は型アノテーションなしで宣言することができます。

```swift
var integerArray = [0] // Int型の配列として定義される
var stringArray = ["りんご"] // String型の配列として定義される
var unknownArray = [] // 型が推測できないためエラー
```

基本的な情報としてはこれくらいですが、Swiftの配列操作は色々な機能があるので別途まとめます。

### 辞書
配列と同様に複数の値を格納するための型です。配列を拡張したようなものです。
配列は格納した要素を配列番号(**インデックス**)で管理しますが、辞書では**キー**で管理します。
キーとは検索ワードのようなものをイメージしてもらえるとわかりやすいかと思います。
辞書はkey-valueの形でキーと値をワンセットとして保持します。
<img width="502" alt="辞書.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/ddbbd0ee-ff27-f160-e40b-3a9756ea95f4.png">

辞書は`Dictionary`型ですが配列と同様に値の型、さらにキーの型を一緒に宣言してあげる必要があります。
辞書も当然宣言した型以外のものを入れるとSwiftからエラーが表示されます。
宣言の仕方は`var 名前: [キーの型: 値の型] = 初期値`となります。

```swift
// キーがString, 値がString
var stringDictionary: [String: String] = ["apple": "りんご", "orange": "オレンジ", "banana": "バナナ"]

// キーがString, 値がInt
var intDictionary: [String: Int] = ["apple": 1, "orange": 1, "banana": 5]

// キーがInt, 値がString
var keyIntDictionary: [Int: String] = [1: "りんご", 3: "オレンジ", 5: "バナナ"]
```

初期化の際注意が必要なのはキーが重複しないようにしてください。
同じキーを定義してもSwiftからエラーが返ってきませんが、初期化されるタイミングでアプリがクラッシュするようです。
値は同じ値があっても問題ありません。

値へのアクセスは`辞書名[キー名]`です。

```swift
// 参照
print(stringDictionary["apple"]) // りんご
print(intDictionary["banana"]) // 5
print(keyIntDictionary[3]) // オレンジ

// 更新
stringArray["apple"] = "アップル"
print(stringArray["apple"]) // アップル
```

また当然初期値は空でもよく、変数で宣言した場合は追加/削除することができます。
追加は更新と同じ方法で`辞書名[キー名] = 値`です。格納先のキーが存在しない場合は新しい要素として追加されます。
削除は`辞書名.removeValue(forKey: キー名)`

```swift
// 配列の初期値を空で宣言
var dictionary: [String: String] = [:]
// 追加処理
dictionary["apple"] = "りんご"
dictionary["orange"] = "オレンジ"
print(dictionary) // ["orange": "オレンジ", "apple": "りんご"]

// 削除処理
dictionary.removeValue(forKey: "apple")
print(dictionary) // ["orange": "オレンジ"]
```
※意識することは少ないかもしれませんが配列と違い、辞書型では登録した順番は担保されずどのような順番で保持されているかはわかりません。

型宣言についても配列と同様、空以外の初期値を与えてあげると型推論することができます。

このように辞書型は配列と似たような性質であることがわかります。
配列はインデックスという順番で管理し、辞書はキーという実装者が見て意味がわかりやすいもので管理すると覚えておいてください。

余談ですが辞書型は別の言語では**連想配列**と呼ばれたりもします。

## 最後に
変数、型、基本型の種類にについては以上です。
これくらいあればある程度表現できるではないでしょうか？

本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/