Swiftの変数の宣言とデータ型について
はじめに
今回は、Swiftにおける変数の宣言方法と、標準で用意されているデータ型の概要を駆け足で見ていくことにしましょう。前回、前々回で紹介したPlaygroundを使用して実際にコードを入力して確認しながら読み進めても良いでしょう。
変数の宣言について
Swiftでは変数の宣言を、varキーワードを使用して行います。
var 変数名:型
例えばInt型の変数ageを宣言して、値に「44」を代入するには次のようにします。
var age:Int age = 44
次のように1行で記述しても構いません。
var age:Int = 44
型の推論機能
上記の例では、Objective-Cにおける変数宣言と同じように、型を明示していました。これを「型アノテーション」と呼びます。Swiftでは、宣言と同時に値を代入する場合、型アノテーションなしに型を判定してくれる「型推論機能」が用意されています。次に例を示します。
var age = 44 // Int型 var name = "山田太郎" // String型 var rate = 104.5 // Double型
上記のように、代入する値が整数の場合にはInt型、文字列はString型、浮動小数点数の場合にはDouble型と判断されます。なお、カンマ「,」で区切ることにより、複数の変数を1行で宣言できます。
var year = 2018, pref = "東京都", weight = 55.5 // <-Int型、String型、Double型
Swift 3以降では、値の型名を取得するためにtype(of:)関数を使用します(Swift 2以前に型名を取得するのに使用されていたdynamicTypeプロパティは廃止されました)。
var age = 44 print(type(of: age)) // -> Int
定数として宣言する
varキーワードの代わりにletキーワードで宣言した場合は定数扱いとなり、後から値を変更できなくなります。
let birthYear = 1985 // letで定数として宣言 birthYear = 1986 // <-エラー
整数型について
整数の値を管理するデータ型の代表がInt型です。変数を宣言して値を代入すると、型推論によりInt型となります。それ以外にもデータ長に応じて、「符号付整数型」と「符号なし整数型」が各4種類、合計8種類の整数型が用意されています。
符号付き整数型 | 符号無し整数型 | データ長 |
---|---|---|
Int | UInt | 32ビット環境では32ビット、64ビット環境では64ビット |
Int8 | UInt8 | 8ビット |
Int16 | UInt16 | 16ビット |
Int32 | UInt32 | 32ビット |
Int64 | UInt64 | 64ビット |
IntおよびUIntは、32ビット環境と64ビット環境でビット長が異なります。ただし、XcodeのSwiftで作成可能なMacアプリは、64ビット版のみです。また、iOS11以降は32ビットアプリは完全に対象外となったため、現在ではInt = Int64、UInt = UInt64と考えて良いでしょう。
なお、Int型以外の整数型を使用するには、型アノテーションが必要です。例えばInt8型の変数pointを宣言して、値に「95」を代入するには次のようにします。
var point:Int8 = 95
また、これらの型は全て構造体(struct)として定義されています。例えば、Int8型はInt8構造体として定義され、maxプロパティで最大値、minプロパティで最小値を表示できます。
print(Int8.max) // -> 127 print(Int8.min) // -> -128
浮動小数点型について
浮動小数点型は、小数点以下の値を持つ数値(実数)を表すための型です。SwiftではDouble型とFloat型の2種類の構造体が用意されています。
型 | データ長 |
---|---|
Float | 32ビット |
Double | 64ビット |
型アノテーションなしで宣言するとDouble型になります。
var num1 = 3.14 // Double型
Float型の変数を宣言するには、明示的に型を指定する必要があります。
var height:Float = 174.5 // Float型
Swift 3以降では、型のデータ長を調べるには「MemoryLayout<T>.size」を使用します(Swift 2以前に用意されていたsizeof()関数は廃止されました)。
print(MemoryLayout<Int>.size) // -> 8 print(MemoryLayout<Float>.size) // -> 4 print(MemoryLayout<Double>.size) // -> 4
Swiftは型に厳格
Swiftは型に厳格な言語です。例えばObjective-Cの場合、次のようにint型の値をdouble型の変数に代入できました。
int a = 5; double b; b = a;
上記の例のように、代入によって値の精度が変わらないケースでも、Swiftではエラーになります。
var a:Int = 5 var b:Double; b = a // <- エラー
Int型の値をDouble型の変数に入れたい場合は、次のようにDouble型のイニシャライザを使用して、Int型をDouble型に変換してから代入する必要があります。
b = Double(a)
前述の例では整数と浮動小数点数の間での変換でしたが、Int8型とInt型といったように、同じ整数型同士でも、型が異なる場合には変換が必要になります。
var num1:Int8 = 34 var num2:Int = Int(num1) + 1 // Int8型をInt型に変換
文字列はString型
Swift標準の文字列は、String構造体のインスタンスです。Objective-Cと同様に、文字列リテラルはダブルクォートで囲みます。次にString型の変数strを宣言して、"こんにちは"を代入する例を示します。
var str:String = "こんにちは"
型アノテーションを省略した場合には、自動的にString型と見なされます。
var str = "こんにちは"
また、Objective-Cでは文字列の連結にはstringWithFormat:メソッドを使用していましたが、Swiftでは+演算子で簡単に連結できます。
var yourName = "山田" + "花子" // "山田"と"花子"を連結
NSStringのクラスの利用
Swiftでも、Objective-Cで使用されていたFoundationフレームワークのNSStringクラスを使用することが可能です。
var name:NSString = "田中一郎"
NSString型とString型は相互変換可能です。NSString型の文字列を、String型にキャストするには次のように「変数名 as String」を使用します。
var str:String = name as String
文字数を正しくカウントできる
Swiftの文字列に特徴的なのは、いくつかのビュー(view)という概念で文字列を操作できるようになっている点です。例えば、CharacterViewでは文字列を画面での見た目の文字として、UTF16Viewでは文字エンコーディングUTF-16のバイト列データとして扱うことが可能です。ここで言う「見た目の文字」とは、エディタでのカーソルの移動単位と考えてください。
String型の詳細についてはまた別の機会に解説するので、ここではCharacterViewを使用すると、文字列を見た目の文字そのものとして扱えると覚えておいてください。
例えば、Swift 3までは文字列の長さを求めるには、charactersプロパティでCharacterViewを取得し、そのcountプロパティを使用していました。
var str:String = "こんにちは" print(str.characters.count) // -> 5
Swift 4では、String型のcountプロパティで文字列の長さを取得することができるようになりました。
print(str.count) // -> 5
これは、Objective-Cで標準であったNSString型のlenghtプロパティを使用した結果と同じです。
var nsStr:NSString = "こんにちは" print(nsStr.length) // -> 5
NSStringとStringの大きな相違が、「1文字」の取り扱いです。例えば、前者はUTF-16のバイト列で文字を管理し、lengthプロパティはその長さを戻すため、必ずしも見た目の文字数とは限りません。それに対してcountプロパティはきちんと文字数を戻します。
例を示しましょう、Unicodeでは「だ」という文字は、「だ」(U+3060)の他に「た」(U+305f)+ 濁点(U+3099)の組み合わせでも表現できます。NSString型では後者の表現を2文字と認識しますが、String型の場合は正しく1文字となります。次に、「たかだ」という文字列の長さを求める例を示します。
var str = "たかた" + "\u{3099}" // たかだ print((str as NSString).length) // -> NSString型では4文字 print(str.count) // -> String型では3文字
またUnicode 6.0で追加された国旗の絵文字は、2文字の国コードリストから構成されますが、UTF-16では2文字ともサロゲートペアとなるため、NSString型では4文字としてカウントされます。それに対してString型では、正しく1文字とカウントされます(Unicodeは当初全ての文字を2バイトで表現することを目的としていましたが、近年新たにUnicodeに組み込みたい文字が増えてきたため領域が不足してきました。そのため、新たに追加する文字を4バイトで管理する仕組みとして、サロゲートペアが考案されました)。
var str = "🇯🇵" // U+1F1EF + U+1F1F5(strは日本の国旗の絵文字だが、環境によってはJPと表示される) print((str as NSString).length) // -> NSString型では4文字 print(str.count) // String型では1文字
コレクションについて
Swiftでは、コレクションとして配列(Array)、辞書(Dictionary)、集合(Set)といった構造体が用意されています。これらは、それぞれObjective-Cで使用されていたFoundationフレームワークのNSArray(およびNSMutableArray)、NSDictionary(およびNSMutableDictionary)、NSSet(NSMutableSet)といったクラスを置き換えるものです。またSwiftでは、フレームワークではなく、言語に組み込まれた構造体として定義されています。コレクション全体については連載が進むにつれて詳しく説明することにして、ここでは配列(Array構造体)を簡単に紹介しましょう
配列を使ってみる
Foundationフレームワークの配列の場合、ミュータブルな配列はNSMutableArrayクラス、イミュータブル(変更できない)な配列はNSArrayクラスと個別に用意されていました。それに対してSwiftでは、varで宣言すればミュータブル、letで宣言すればイミュータブルになります。配列リテラルの書式はObjective-Cと同じく、要素をカンマで区切り、全体を「[ ]」で囲みます。
// ミュータブルな配列を宣言 var countries = ["アメリカ", "日本", "中国", "イギリス"] // 2番目の要素を変更する countries[1] = "ドイツ"
for~inループで配列の要素をイテレートできます。
for c in countries { print(c) } 実行結果 アメリカ ドイツ 中国 イギリス
タプルについて
Objective-Cにはない、一連のデータを管理する機能として、Swiftには「タプル(tuple)」があります。タプルとは複数の値をまとめて、一つの値のように扱う仕組みです。Pythonなどのメジャーな言語にも用意されているので、ご存知の方も多いでしょう。タプルのリテラルは次のような書式になります
(値1, 値2, 値3, ...)
値は型が異なっていても構いません。次に、顧客の番号、名前、年齢を管理するタプルcustomerを、型アノテーション付きで宣言する例を示します。
var customer:(Int, String, Int) = (101, "江藤三四郎", 43)
型アノテーションを省略しても構いません。
var customer = (101, "江藤三四郎", 43)
タプルの各要素には、「変数名.番号」でアクセスできます(番号は先頭の要素を0とする整数値)。
print(customer.1) // -> 江藤三四郎 customer.2 = 44 // 3番目の要素を44に変更
それぞれの要素に名前を付ける
値の前に「名前:」を記述することにより、それぞれの要素に名前を付けることができます。
var customer = (number:101, name:"江藤三四郎", age:43)
以上で、「変数名.要素名」でアクセスでます。
var hisName = customer.name // nameをhisNameに代入 customer.age = 44 // ageを44に変更
タプルの値をそれぞれ変数に代入する
タプルの要素の値を個別の変数に代入するには、左辺の「( )」内にカンマで区切って変数を記述します。
var customer = (number:101, name:"江藤三四郎", age:43) var (number, name, age) = customer
このとき値が不要な要素は、その部分にアンダースコア「_」を記述します。
var colors = ("red", "blue", "green") var(c1, _, c3) = colors // c1に"red", c3に"green"が代入される