1から始めるSwift言語。SwiftでiPhoneApp製作 その7 基本的なデータ型、Optional型、値型と参照型(ClassとStruct)
2016.02.19
この記事は最終更新日から1年以上が経過しています。
前回の
1から始めるSwift言語。SwiftでiPhoneApp製作 その6 PlaygroundでSwift記述
の続きとなります。
1から始めるSwift言語。とタイトルにしながら全然Swiftを書いていないのですが、
いよいよですね。
まず、どこから書きましょうか。。
どうやらswiftと言う言語は、Objective-C, Rust, Haskell, Ruby, Python, C#, CLUなどから影響を受けている
ようで、「あの言語に似ている。」と言ったシーンも出てくる事でしょう。
大きな特徴の一つとして、変数と定数の定義でしょうか。
また、Swiftでは、クラスから作られた実体のほか、整数、構造体などのデータ型を含め型の実体を全てインスタンス(instance)と総称します。
このようなデータ型の中に、「値型」と「参照型」と存在するのですが、後半辺りにまとめるとして、そのほかに
Swiftではポインタの概念もなく、より扱いやすくなっているのが特徴の一つでしょう。
主な特徴
・色んな言語に影響を受けている
・変数と定数
・実体を全てインスタンスと総称
・「値型」と「参照型」
・型推論
・ポインタの概念がない
基本的なデータ型
種類 | 型名 | 詳細 |
整数型 | Int | 整数全般に対する利用が推奨されている |
整数型 | Unit | 符号のない整数型 |
実数型 | Float | 浮動小数点 |
実数型 | Double | 浮動小数点。より精度が高い |
論理型 | Bool | リテラルはtrueとfalse。整数型ではない |
文字 | Character | Unicodeの1文字を表す。整数型ではない |
文字 | UnicodeScalar | Unicodeの文字コードを表す |
文字列 | String | 文字列の内容は変更可能 |
変数と定数
変数
変数の宣言は、JavaScriptでもおなじみの
var
を使って宣言します。
var age : Int var 変数名 : 型 = 式
Swiftでは型推論が行われますので、型や式は省略可能となっております。
var age : Int = 18 //型宣言と初期値を記述 var age = 18 //初期値から型を推論(整数型) age = 30 // varで宣言した変数の値を変更できる
(型宣言せずに初期値を設定する方法が推奨されています。)
定数
また、もう一つ「let」を使用できるのですが、こちらは定数の宣言となります。
let
let 定数名 :型 = 式
こちらは型のみ省略が可能となっております。初期値の省略できません。
また、定数の宣言となりますので後で値を変更する事もできません。
let age = 18 age = 30 //エラー
ES6でも「let」の宣言がありますが、そちらとは若干異なるようで、
ES6では、「ブロックスコープ内の宣言」となり、「巻き上げしない変数」となっております。
Swiftの letは「定数」の宣言となりますので、途中で値を変更しようとすると、コンパイルエラーが発生しコンパイルが行えません。
また、変数を途中で変更しない場合は、letに変更しましょう。と警告されたりします。
型推論
Swiftは型に関して厳密な言語です。基本的には、変数や定数に定義した以外の型の値の代入は許されていません。
let i: Int = 10 var a: Double = i
ですが、上記でも記載したように、swiftではObjective-Cのように明示的に型を書かなくても型を推論してくれます。
let i: Int = 10 var a = i
明示的に型を指定する場合、整数と実数の間だけでなく、Int型やUInt型、Float型とDouble型などでもエラーが発生することを気をつけなければいけません。
let r:Double = 0.1 var f: Float = r //エラー
let w: Double = 0.5 let i:Int = 10 let b = w * i //エラー
このようにC言語のような「暗黙の型変換」は行われません。
JavaScriptを書いている人には抵抗があるかも知れませんが、いわゆるAltJSである、TypeScriptでは静的型付けの仕様となっておりますので、JavaScriptでもこう言った型付けは可能となっております。
TypeScriptに慣れると型付けが自然となってきますので、フロントエンドの方も慣れておくといいかもしれませんね。
文字列・文字型
String
Swiftの文字列はString型のインスタンスとなります。
var str: String = "Hello, playground"
文字列を連結する場合は「+」を使って連結する事が可能です。
var str: String = "Hello! " var name = "takayama" print(str + name)
また、ダブルクォーテーションで囲んだ文字列内に「\()」で式を代入する事もできます。
これを、文字列埋め込み(string interpolation)といいます。
let n = 8 let str = "\(n)の2乗は\(n*n)です。" //"8の2乗は64です。"
Rubyでいうところの #{} ですかね。
Character
また、String型とともに使われる型にCharacter型があります。
Character型は、Unicode文字を1文字格納する文字型となっています。
let atmark: Character = "@" let arrow = Character("→")
Character型同士の連結は行えません。
var a = atmark + atmark //エラー
String | Unicode文字を連ねた文字列を格納する可変長文字列型 |
Character | Unicode文字を1文字格納する文字型 |
数値型
数値データを表す型としては、Int型、Double型、Float型の他にも、以下の表のような型が用意されています。
ビット幅が指定された整数型と符号なし整数型は、CやObjective-Cとデータのやりとりをする場合の制約を明らかにする目的で使用したりします。
C言語とは異なり、演算結果がその型で扱える最大値、最小値を超える場合エラーとなってしまいますので、Swiftでは制約の必要性がない場合は、Int型を使用する事が推奨されています。
let int = 10 var sum = int + 3
異なる型の演算子はエラーとなります。
let int = 10 var sum = int + 3.2 //エラー
Float型、Double型を定義するか、
let number: Float = 10 var sum = number + 3.2
変数定義の際に、.0を付与して型推論を行うかすれば解決できます。
let number = 10.0 var sum = number + 3.2
また、演算結果がその型で扱える最大値を超える場合エラーとなってしまいます。
let number: Int8 = 100 var sum =number + 28 //エラー
(避ける方法としてオーバーフロー演算子などがありますが今回はとりあえず置いておきます。)
符号付き整数型
Int8 | -128〜127 の整数 |
Int16 | -32,768〜32,767 の整数 |
Int32 | -2,147,483,648〜2,147,483,647 の整数 |
Int64 | -9,223,372,036,854,775,808〜9,223,372,036,854,775,807 の整数 |
Int | 32ビット環境ではInt32、64ビット環境ではInt64と同じ範囲の整数値をとる |
符号無し整数型
UInt8 | 0〜255 の整数 |
UInt16 | 0〜65,535 の整数 |
UInt32 | 0〜4,294,967,295 の整数 |
UInt64 | 0〜18,446,744,073,709,551,615 の整数 |
UInt | 32ビット環境ではInt32、64ビット環境ではInt64と同じ範囲の整数値をとる |
浮動小数点
Float | 32ビット浮動小数点。Doubleほどの精度を必要としない場合に使用する |
Double | 64ビット浮動小数点。小数点を扱う場合は主にこちらを使用する |
真偽値型
Swiftの真偽値はBool型となります。
リテラルはtureとfalseとなります。
var isWebcyou = true if isWebcyou { print("web帳") }
Bool | リテラルはtrueとfalse。整数型ではない |
配列型
配列に関しても、JavaScriptなどの言語と大きく異なる事はなく、[] を用いて配列を生成します。
var arr = ["web帳", "ウェブ帳", "webcyou"]
型指定する場合は[]の中に指定する事になり、
var arr: [String] = ["web帳", "ウェブ帳", "webcyou"]
TypeScriptなどでは、[]の前に指定ですので、TypeScriptとは若干異なりますね。
var array = [17, 25, 13, 47] print(array[2]) // "13\n" print(array.count) // "4\n"
添字による取り出しも可能で、countで要素の数も取り出せます。
要素の変更
要素の変更も他言語と同様の形で行えます。
var arr: [String] = ["web帳", "ウェブ帳", "webcyou"] arr[0] = "うぇぶちょう" print(arr) //"["うぇぶちょう", "ウェブ帳", "webcyou"]\n"
もちろん、異なる型で演算しようとするとエラーが発生いたします。
let num: [Int] = [12, 13, 11] print(num[2] + 1.3)
適切な型の指定を行いましょう。
let num: [Double] = [12, 13, 11]
要素の追加、削除
配列の要素追加は「append」関数を用いて行う事ができます。
var array = [17, 25, 13, 47] array.append(56) //[17, 25, 13, 47, 56]
逆に削除は、「removeAtIndex」 関数で削除する要素の順番を指定して削除を行えます。
array.removeAtIndex(3) print(array) //"[17, 25, 13, 56]\n"
また、「sort」関数で要素のソートも行えます。
array.sort() //[13, 17, 25, 56]
イテレーション
作成された配列は、for文を用いて取り出す事が可能です。
var arr:[Double] = [8, 3, 9, 91] for x in arr { print(x) //(4 times) }
上記の様に、for x in を用いて、for文内でxの値を変更しようとしても、変更後の値は保持できないので、
値を変更したい場合は、以下の様に 「enumerate」関数を用いると良いでしょう。
var arr:[Double] = [8, 3, 9, 91] for x in arr { print(x + 1) // 9.0, 4.0, 10.0, 92.0 } print(arr) // "[8.0, 3.0, 9.0, 91.0]\n"
enumerateを使用。
var arr:[Double] = [8, 3, 9, 91] for (index, value) in arr.enumerate() { arr[index] = value + 1 } print(arr) // "[9.0, 4.0, 10.0, 92.0]\n"
辞書型(ディクショナリ)
ディクショナリは、文字列や数値をキーにして値を格納したり参照できる型 となっております。
[]を用いて、:で区切った キーと値のペアで生成する事ができます。
var dictionary = ["blog": "web帳", "author": "daisuke takayama"] print(dictionary["blog"]!) //"web帳\n"
countプロパティで要素をカウントできます。
print(dictionary.count)
添字で指定して変更も可能です。
dictionary["blog"] = "Webcyou"
「removeValueForKey」で、キーを指定して、要素の削除も行えます。
dictionary.removeValueForKey("blog") print(dictionary) //"["author": "daisuke takayama"]\n"
Optional型
Swiftの大きな特徴で避けては通れないのが(笑)こちらのOptional型となっております。
オプショナル型とは、変数の型がもつ通常の値に加えて、空の(値が無い)状態を保持できる変数となっております。
変数の宣言時に、型の後ろに「?」をつけて宣言する事によってオプショナル型の定義を行えます。
var name: String? name = nil //OK
var name: String name = nil //エラー
また、Optional型の変数は値を取り出す場合は、強制的アンラップ(Forced Unwrapping)する必要があります。
var name: String? name = "takayama" print(name) // "Optional("takayama")\n" //強制アンラップ print(name!) // "takayama\n"
と、これ以上書くとボリュームが凄い事になりそうなので、一旦ここまでで別記事でまとめられればと思います。
値型と参照型(ClassとStruct)
今回の最後として、Swiftの特徴として、値型(value type)と参照型(reference type)についてちょこっと。
C言語などの言語にある様に、数値データは、変数に代入したり関数に渡したりする時にコピーが作成されるため、その後の演算や操作は元データに影響しません。
Swiftではこのようなデータ型を値型(value type)といいます。
また、これに対して代入の際にコピーを作るのではなく、データ自体に対する参照を渡す型の事を参照型(reference type)と呼びます。
では、どんなものなのかと言いますと、値型(value type)はStruct、参照型(reference type)はClassのインスタンスが代表的な例かと思います。
Struct
Structは構造体となります。
Structの特徴としましては、辞書とは違い、同じ構造のオブジェクトを複製することができ、クラスとは違い、継承はできません。
また、構造体は値型として振る舞われます。
記述は以下の通りで、
struct 名前 { var hoge:型 let fuga:型 }
初期値なしでも、ありでも書く事が可能となっています。
struct Blog { var name:String var url:String } // インスタンス作成時に初期値を入れる。 var blog = Blog(name: "web帳", url: "https://www.webcyou.com/") print(blog.name) // "web帳\n"
初期値ありの場合
struct Blog { var name = "web帳" var url:String = "https://www.webcyou.com/" } var blog = Blog() print(blog.url) // "https://www.webcyou.com/\n"
Class
Classに関しては多くの説明は不要かと思いますので、とりあえずStructと異なり、参照型というのを記載しておきます。
クラスの定義
class 型名:スーパークラス { 変数/定数定義 イニシャライズ定義 メソッド定義 その他の定義 }
ここで、Classとstructを比較してみます。
// 構造体(値型) struct BlogStruct { var name:String } // クラス(参照型) class BlogClass { var name:String init(name:String){ self.name = name } } var blogStruct1 = BlogStruct(name: "web帳") var blogStruct2 = blogStruct1 blogStruct1.name = "はてなblog" print("blogStruct1:\(blogStruct1.name)、blogStruct2:\(blogStruct2.name)")
blogStruct2にblogStruct1を代入した後、blogStruct1.nameを変更したのですが、
結果は”blogStruct1:はてなblog、blogStruct2:web帳\n”
と、blogStruct2は影響いかないのに対して、classでは、
var blogClass1 = BlogClass(name: "web帳") var blogClass2 = blogClass1 blogClass2.name = "はてなblog" print("blogClass1:\(blogClass1.name)、blogClass2:\(blogClass2.name)")
同様の処理を行った結果は、”blogClass1:はてなblog、blogClass2:はてなblog\n”
と、blogClass2に影響が及んでいるのが確認できます。
StructをJavaScriptで実現しようとすると、オブジェクトは参照渡しとなりますので、ディープコピーですかねぇ。
と、こちらもより詳細を書いていこうとすると、結構な量となるため、今回は一旦ここで締めさせていただきます。
ではではー。