プログラミング初心者、初級者に向けてSwiftをベースとした変数宣言、型の種類について紹介していきます。
変数
プログラミングでは処理をする際様々なデータを扱います。
このデータはコンピュータの記憶領域(メモリ)に保存されます。
プログラミングではこのメモリに変数名前を付け、変数経由でメモリの読み書きをします。
変数を扱う前には「今からこんな名前の変数を使います」とコンピュータに教えてあげる必要になります。
これを変数を宣言するとか定義するとか言ったりします。
以下の例はx
という名前の変数をInt型で宣言しています。(※型については後述)
var integer: Int
宣言した後はinteger
という名前でメモリにアクセスすることができます。
integer
という名前の箱をメモリに準備し、その中のデータを参照したり更新するというようなイメージです。
変数・定数
先述した説明ではデータの扱いはまとめて変数といってますが実際には変数と定数があります。
それほど違いはなくイメージのまま変数は読み書き可能で、定数の場合書き込みは初期化の時のみでその後はデータの更新はできません。
宣言の仕方が変数と定数では少し異なり、変数の場合はvar
、定数の場合はlet
をそれぞれ宣言時に付けます。
var variable: Int = 0
variable = 10 // 変数は書き換え可能
let constant: Int = 0
constant = 10 // 定数は読み込みのみなのでエラー
書き換えの必要がないものにはlet
を使ってあげましょう。
型について
変数を扱う際は型というものを意識します。
型とは扱う変数がどんな種類でどんな性質を持っているのかなど、そのデータの特性を表すものです。
代表的なものとしては文字列を扱うString型、整数を扱うInt型などが挙げられます。
変数は指定された型しか扱えません。
例えばInt型で宣言した変数に文字列を格納しようとしてもプログラムは理解できずエラーとなります。
var integer: Int = 0
integer = "文字列を代入" // 型が異なるためエラー
(補足ですが文字列は"~"
で表されます)
このように明確に型を付けてあげることを型アノテーションといいます。
もし型というものがなければ、例えば金額の計算をしていたのにいつの間にか「ああああ111」という結果になってしまうということもありえます。
そうなるとアプリが実装者の意図した挙動をしない可能性が出てきます。それを未然に防ぐためにSwift自体がエラーを出してくれます。
余談ですがSwiftなどはコンパイラ言語と呼ばれ型宣言を必要としています。一方でスクリプト言語と呼ばれるJavaScriptやPHPなどでは型がありません。
そのためスクリプト言語ではいつの間にか変数が文字列に変わっていたということは発生したりします。これは実装者がそうならないように気をつけて実装していく必要があります。
メモリアドレス
少し変数宣言について内部処理の話をします。少し難しいかもしれないので、理解できなければそんな感じなのかーくらいの認識を持つ程度で大丈夫です。
そこまで気にしなくてもSwiftはとりあえずは書けます。
実際、変数にはアドレスと呼ばれるメモリの場所、住所が記録されています。
メモリはコンピュータから1bitに対し1アドレスが割り当てられています。(1byte毎かもしれません。。)
アドレスは整数で定義されており16進数で表されることが多いです。
そしてメモリ1つ1つに対して0 or 1のデータが格納されています。
変数は扱うデータを表すメモリ領域の先頭のアドレスを持ちます。
先頭アドレスがわかればどこにデータの内容が確保されているかわかります。
では先頭はわかりましたがこの変数はどのメモリまでをデータとして扱えばいいのでしょうか?
それを表すのが型です。
型にはそれぞれ必要とする長さが決まっています。
(全部がそうではありませんがそういったイメージでいいです)
環境によって変わったりしますがIntなら64bitを確保します。
このようにしてどこからどこまでを1つのデータとして扱うかを決めています。
結局扱う際はこのデータのまとまりを1データとして扱うためIntとして大きな箱がメモリに準備されると思ってもらえれば問題ありません。
型推論
さて、ここまで変数には型が必要だと説明してきましたが、実はSwiftでは実装者が型アノテーションで明確に型を宣言しなくても良い場合があります。むしろそのパターンの方が多かったりします。
この機能を型推論といい、読んで字のごとく型を推測してくれます。
例えばIntの場合以下のように定義することができます。
let integer = 0
このように宣言した場合、Swiftの方で勝手にこれは整数を扱っているからInt
型だなというように推測してくれ、その後はInt型として扱うことができます。
型推論とはいえSwift側では型を明確にできるためIntと推論されたものに対しては文字列は代入できません。
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
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
型になります。
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
型のみと思っていいです。
型アノテーションなしで使用できます。
let string: String = "文字列"
論理型
Bool
型。真偽値を扱います。
値はtrue/falseのみです。
型アノテーションなしで使用できます。
主に条件判定の際に使います。
var boolean: Bool = true
var equalBoolean = 0 == 0
配列
「配列」とは複数の値を格納するための型です。
画像を見たほうが想像が付きやすいと思います。
少し注意が必要なのは配列の最初が0番目から始まることです。
数学の数列などでは1番目から扱うことが多いですがそこは異なっています。
配列はArray
型ですが、宣言の仕方が少し特殊です。
配列には変数を格納していくため、その変数自体の型情報も一緒に定義してあげる必要があります。
宣言した型以外のものを入れるとSwiftからエラーが表示されます。
宣言の構文はvar 名前: [型] = 初期値
です。
var integerArray: [Int] = [0, 1, 5, 19] // Intを格納する配列
var stringArray: [String] = ["りんご", "みかん", "バナナ"] // Stringを格納する配列
配列名[n]
で格納した値にアクセスすることができます。
// 参照
print(integerArray[0]) // 0
print(stringArray[2]) // バナナ
// 更新
stringArray[0] = "パイナップル"
print(stringArray[0]) // パイナップル
また初期値は空でもよく、さらに変数として宣言している場合後から追加、削除できます。
追加は配列名.append(追加する要素)
削除は配列名.remove(at: 削除する要素の配列番号)
※append
は配列の一番後ろに要素を追加します。他にも間に挿入するなどもあります。
// 配列の初期値を空で宣言
var stringArray: [String] = []
// 追加処理
stringArray.append("りんご")
stringArray.append("みかん")
print(stringArray) // ["りんご", "みかん"]
// 削除処理
stringArray.remove(at: 0)
print(stringArray) // ["みかん"]
補足として配列を定数として宣言した場合、更新はできません。
append
やremove
も同様に使えません。
let constantArray: [String] = ["りんご", "みかん"]
// 更新できない
constantArray[0] = "パイナップル" //エラー
constantArray.append("メロン") // エラー
constantArray.remove(at: 0) // エラー
// 参照はできる
print(constantArray) // ["りんご", "みかん"]
print(constantArray[0]) // "りんご"
また、配列は初期値が空でない場合は型アノテーションなしで宣言することができます。
var integerArray = [0] // Int型の配列として定義される
var stringArray = ["りんご"] // String型の配列として定義される
var unknownArray = [] // 型が推測できないためエラー
基本的な情報としてはこれくらいですが、Swiftの配列操作は色々な機能があるので別途まとめます。
辞書
配列と同様に複数の値を格納するための型です。配列を拡張したようなものです。
配列は格納した要素を配列番号(インデックス)で管理しますが、辞書ではキーで管理します。
キーとは検索ワードのようなものをイメージしてもらえるとわかりやすいかと思います。
辞書はkey-valueの形でキーと値をワンセットとして保持します。
辞書はDictionary
型ですが配列と同様に値の型、さらにキーの型を一緒に宣言してあげる必要があります。
辞書も当然宣言した型以外のものを入れるとSwiftからエラーが表示されます。
宣言の仕方はvar 名前: [キーの型: 値の型] = 初期値
となります。
// キーが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からエラーが返ってきませんが、初期化されるタイミングでアプリがクラッシュするようです。
値は同じ値があっても問題ありません。
値へのアクセスは辞書名[キー名]
です。
// 参照
print(stringDictionary["apple"]) // りんご
print(intDictionary["banana"]) // 5
print(keyIntDictionary[3]) // オレンジ
// 更新
stringArray["apple"] = "アップル"
print(stringArray["apple"]) // アップル
また当然初期値は空でもよく、変数で宣言した場合は追加/削除することができます。
追加は更新と同じ方法で辞書名[キー名] = 値
です。格納先のキーが存在しない場合は新しい要素として追加されます。
削除は辞書名.removeValue(forKey: キー名)
// 配列の初期値を空で宣言
var dictionary: [String: String] = [:]
// 追加処理
dictionary["apple"] = "りんご"
dictionary["orange"] = "オレンジ"
print(dictionary) // ["orange": "オレンジ", "apple": "りんご"]
// 削除処理
dictionary.removeValue(forKey: "apple")
print(dictionary) // ["orange": "オレンジ"]
※意識することは少ないかもしれませんが配列と違い、辞書型では登録した順番は担保されずどのような順番で保持されているかはわかりません。
型宣言についても配列と同様、空以外の初期値を与えてあげると型推論することができます。
このように辞書型は配列と似たような性質であることがわかります。
配列はインデックスという順番で管理し、辞書はキーという実装者が見て意味がわかりやすいもので管理すると覚えておいてください。
余談ですが辞書型は別の言語では連想配列と呼ばれたりもします。
最後に
変数、型、基本型の種類にについては以上です。
これくらいあればある程度表現できるではないでしょうか?
本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/