【Swift】辞書型

辞書型とはkeyと値を紐付けたデータを複数代入できる型のことで、アクセスするときは、keyを指定してそのkeyに紐付く値にアクセスします。
辞書型という名前の通り、辞書を引くような使い方をしたい時などに使います。
配列とは違い、インデックス番号は使えません。

前回は while文 について書きました。

今回は 辞書型 について書いていこうと思います。

辞書型とは

辞書型とは key を紐付けたデータを複数代入できる型のことで、アクセスするときは key を指定して、その key に紐付く にアクセスします。
辞書型という名前の通り、辞書を引くような使い方をしたい時などに使います。
配列とは違い、インデックス番号は使えません。

配列型 についてはこちらの記事で紹介しています。

辞書型の書式

//書式1
[keyの型名:値の型名]

//書式2
Dictionary<keyの型名,値の型名>

書式 1
[ ] の中に key の型名を書いて : で区切って値の型名を書きます。
型推論を使って定義することも可能です。

書式 2
Dictionary キーワードを書いて < > の中に key の型名を書いて , で区切って値の型名を書きます。

辞書型を使った例

//例1(書式1)
var geregere:[String:Int]
geregere = ["HP": 200, "MP": 70, "ATTACK": 120]

print(type(of: geregere)) //Dictionary<String, Int>
print(geregere["HP"]) //Optional(200)

//例2(書式2)
var borongo:Dictionary<String,Int>
borongo = ["HP": 180, "MP": 75, "ATTACK": 125]

print(type(of: borongo)) //Dictionary<String, Int>
print(borongo["MP"]) //Optional(75)

//例3(型推論)
var tiroru = ["HP": 190, "MP": 80, "ATTACK": 130]

print(type(of: tiroru)) // //Dictionary<String, Int>
print(tiroru["ATTACK"]) //Optional(130)

例 3 のように型推論を使って書くこともできます。

辞書型はアクセスすると Optional型 で返ってくる

上の例のアクセスした結果を見ると頭に Optional と付いています。
key を指定してアクセスしていますが、あるか分からない key にアクセスする可能性があるためです。
確実にある key だと分かっている場合であれば強制アンラップ ! でアンラップしてもいいですが、そうでない場合の方が多いと思うので、そういう場合は ?? 演算子を使って nil だった場合に代わりに代入する値を指定した方が安全です。

Optional型アンラップ についてはこちらの記事で紹介しています。

辞書型の変数定義〜アンラップしてアクセスする例

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]
print(suraimu["HP"]) //Optional(100)

まだアンラップ前なので、100 の前に Optional が付いています。
これをアンラップしていきます。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]
print(suraimu["HP"]) //Optional(100)

//アンラップしてアクセスする
print(suraimu["HP"] ?? "nil") //100

?? 演算子を使って、アクセスした key “HP”nil だった場合は文字列の “nil” を代入します。
これで出力されている値は 100 になったので、
Optional型 から Int型 にアンラップすることができました。

次は key に無いものを指定して、結果が変わるか見てみます。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]
print(suraimu["HP"]) //Optional(100)

//アンラップしてアクセスする
print(suraimu["HP"] ?? "nil") //100

//keyに無いものを指定してみる
print(suraimu["Defense"] ?? "nil") //nil

key“Defense” と指定して、keynil だった場合は文字列の “nil” を代入します。
結果は “nil” になります。
“Defense” という key は定義していないので( nil なので )、右辺の “nil” が代わりに代入されます。

dictionaryコードimg

要素の順番は保証されない

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//要素の順番は保存されない
for i in suraimu.keys {
    print(i)
}

//実行結果
/*
ATTACk
HP
MP
*/

配列型とは異なり、辞書型は要素を順番で管理しないので参照するたびに順番が変わります。そのためインデックス番号が使えません。

要素の追加と変更方法

追加または変更の書式

変数名、または定数名[key] = 値

要素の追加

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//要素の追加
suraimu["Defense"] = 10
print(suraimu) //["HP": 100, "ATTACK": 50, "Defense": 10, "MP": 30]

要素の変更

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//要素の追加
suraimu["Defense"] = 10
print(suraimu) //["HP": 100, "ATTACK": 50, "Defense": 10, "MP": 30]

//要素の変更
suraimu["Defense"] = 20
print(suraimu) //["HP": 100, "ATTACK": 50, "Defense": 20, "MP": 30]

追加したい key が既存でなければ追加、key がもし既存のものであれば値の変更になります。

要素の削除

removeValue(forKey:) メソッド

辞書型の要素を削除したいときは、removeValue(forKey:) メソッド を使います。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//要素の追加
suraimu["Defense"] = 10
print(suraimu) //["HP": 100, "ATTACK": 50, "Defense": 10, "MP": 30]

//要素の変更
suraimu["Defense"] = 20
print(suraimu) //["HP": 100, "ATTACK": 50, "Defense": 20, "MP": 30]

//要素の削除
//removeValue(forKey:)メソッド
suraimu.removeValue(forKey: "Defense")
print(suraimu) //["HP": 100, "ATTACK": 50, "MP": 30]

removeValue(forKey:) メソッドの引数に削除したい key 指定します。 key が既存であれば削除することができます。

辞書型とよく使うメソッドとプロパティ

.contains メソッド

.contains メソッドは、指定した要素が含まれているかどうかを Bool値 で返すメソッドです。
指定した要素があれば true
指定した要素がなければ false が返ってきます。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//.containsメソッド
print(suraimu.keys.contains("HP")) //true
print(suraimu.keys.contains("Defense")) //false

.keys プロパティ

.keys プロパティは、key の一覧を取得することができるプロパティです。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//.keysプロパティ
print(suraimu.keys) //["HP", "MP", "ATTACK"]

.values プロパティ

.values プロパティは、値の一覧を取得することができるプロパティです。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//.valuesプロパティ
print(suraimu.values) //[100, 30, 50]

.count プロパティ

.count プロパティは、要素の数を取得することができるプロパティです。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//.countプロパティ
print(suraimu.count) //3

.isEmpty プロパティ

.isEmpty プロパティは、要素が含まれているかどうかを Bool値 で取得することができるプロパティです。
何か要素が入っていれば false
何も入ってなければ true を取得します。
要素が 1 つでも入っていれば false 、空であれば true になります。

var suraimu:[String:Int]
suraimu = ["HP": 100, "MP": 30, "ATTACK": 50]

//.isEmptyプロパティ
print(suraimu.isEmpty) //false
dictionaryコードimg2

辞書型 はコレクション型の 1 つで、配列型 もその 1 つです。
この 2 つの他に 集合型( Set ) というコレクション型もあります。
以上 辞書型 についてでした。

次回は 集合型 について書いていこうと思います。

実行環境

version
Xcode 14.2 (14C18)
Swift 5.2.4

公式ドキュメント

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/

【Swift】Optional型

Optional型( オプショナル型 )とは、nilの可能性があるときに使う型です。
Swiftでは値が無い状態のことを、nilと言います。
例えば、必須項目や非必須項目をユーザーに入力してもらう時など、入力されるか分からない項目がある場合などに Optional型を使います。

前回は タプル について書きました。

今回は Optional型 について書いていこうと思います。

Optional型とは

Optional型( オプショナル型 )とは、nil の可能性があるときに使う型です。
Swift では 値が無い 状態のことを、nil と言います。
逆に言うと、Optional型 で宣言している場合のみ nil を代入する事ができます。
例えば、必須項目 や 非必須項目 をユーザーに入力してもらう時など、入力されるか分からない項目がある場合などに Optional型 を使います。

Optional型の書式

//書式1
型名? 

//書式2
Optional<型名>

型名を書いた後に ? を付けます。( 書式 1 )
または
Optional と書いた後 < > の中に型名を書きます。( 書式 2 )

Optional型 の書き方

//例1
var a:Int?
print(type(of: a)) //Optional<Int>

//例2
var b:Optional<Int>
print(type(of: b)) //Optional<Int>

変数 abOptional型 で宣言しています。
この 2 つの変数の型を見てみると、Optional<Int> となっています。これは Optional Int型 という型で、ただの Int型とは別の型になります。なので原則同じ型でなければ演算できないので、Optional Int型Int型 は演算できません。
Optional型 の値を使いたい時は、アンラップ という処理が必要になります。

Int型 に限らず、他の型でも頭に Optional と付いている型の値を使いたい時はアンラップが必要です。

※ 例 1 は初期値を入れずに宣言するとデフォルトで nil が代入されますが、
例 2 は初期値を入れずに宣言しても nil が代入されません。例 2 はどこかで値を代入しないと使うことができないので注意。

//例1
var a:Int?
print(type(of: a)) //Optional<Int>
print(a) //nil

//例2
var b:Optional<Int> = nil //初期値としてnilを代入
print(type(of: b)) //Optional<Int>
print(b) //nil

Optional型を使った例

必須項目と非必須項目がある場合の例

//必須項目と非必須項目がある場合の例
let name:String //必須項目
var mail:String //必須項目

//Optional型で非必須項目の宣言
var phone:String? //非必須項目
var birthday:String? //非必須項目

//必須項目に値を代入
name = "hoge"
mail = "aaa@123.com"

//アクセス
print("\(name)のアカウント情報") //hogeのアカウント情報
print("アカウント名 \(name)") //アカウント名 hoge
print("メールアドレス \(mail)") //メールアドレス aaa@123.com

//非必須項目にアクセス
print("電話番号 \(phone)") //電話番号 nil
print("誕生日 \(birthday)") //誕生日 nil

必須項目と非必須項目に使う変数・定数を宣言して、必須項目にだけ値を代入し全ての変数・定数にアクセスしている例です。
必須項目には値を代入しているのでこれまで通りアクセスできて値もきちんと反映されています。
次に非必須項目ですが、 値を代入していません。
Optional型 で宣言しているので値の代入がされてなくてもデフォルトで初期値に nil が代入されます。
Optional型nil許す型なので、アクセスしたとき値が無くてもエラーやクラッシュではなく nil が返ってきます。
もしこれを Optional型 ではなく String型 などで宣言していれば、値が無い( 初期値が無い )のにアクセスしてしまいエラーやクラッシュする原因になります。

次は非必須項目に値を入れてアクセスしてみます。

//必須項目と非必須項目がある場合の例
let name:String //必須項目
var mail:String //必須項目

//Optional型で非必須項目の宣言
var phone:String?//非必須項目
var birthday:String? //非必須項目

//必須項目に値を代入
name = "hoge"
mail = "aaa@123.com"

//アクセス
print("\(name)のアカウント情報") //hogeのアカウント情報
print("アカウント名 \(name)") //アカウント名 hoge
print("メールアドレス \(mail)") //メールアドレス aaa@123.com

//非必須項目にアクセス
print("電話番号 \(phone)") //電話番号 nil
print("誕生日 \(birthday)") //誕生日 nil

//非必須項目に値を代入
phone = "123-4567-8910"
birthday = "20XX/XX/XX"

//非必須項目に再度アクセス
print("電話番号 \(phone)") //電話番号 Optional("123-4567-8910")
print("誕生日 \(birthday)") //誕生日 Optional("20XX/XX/XX")

非必須項目にも値を代入して再度アクセスしました。
値を入れずにアクセスした時は nil が代入されていましたが、値を入れてアクセスすると nil ではなく、
phone には Optional(“123-4567-8910”)
birthday には Optional(“20XX/XX/XX”)
が代入されています。
String型 の値を代入したのに、この 2 つの変数は Optional String型 で宣言されているので、頭に Optional が付いた状態になっています。
この状態では print関数 で中の値は確認できますが、実際に値を使うことはできません。
使おうとすると、アンラップする必要があります!とエラーが出ます。

~ ~ ~
//非必須項目に値を代入
phone = "123-4567-8910"
birthday = "20XX/XX/XX"

//非必須項目に再度アクセス
print("電話番号 \(phone)") //電話番号 Optional("123-4567-8910")
print("誕生日 \(birthday)") //誕生日 Optional("20XX/XX/XX")

//Optional String型の変数をString型の変数に入れようとするとエラー
var phoneNumber:String = phone //エラー
optionalコードimg

アンラップ

アンラップとは、ラップ( 包装 )の反対語でラップを外すこと。と表現されている事が多いと思います。
Optional型 はラップ( 包装 )された状態で、このラップを外すことをアンラップと言います。

Optional型の値を 非Optional型 の値と同様に扱いたいときは、アンラップ( unwrap )という処理をしなければ使うことができません。

アンラップする方法

  • ?? 演算子( nil合体演算子 )
  • ! 演算子( 強制アンラップ )
  • if-let文 ( オプショナルバインディング )

この他にも guard-let などいくつかアンラップする方法がありますが、今回は上記の 3 種類を使ってアンラップしていきたいと思います。

?? 演算子 ( nil合体演算子 )

?? 演算子を使ったアンラップの書式

Optional型の値 ?? アンラップ失敗または、nilだった場合に入る値(デフォルト値)

左辺の Optional型の値 がアンラップ可能であれば アンラップした値 を代入し、
アンラップ失敗( 値が nil ) であれば右辺の デフォルト値 を代入する演算子です。

~ ~ ~
//非必須項目に値を代入
phone = "123-4567-8910"
birthday = "20XX/XX/XX"

//アクセス
print("電話番号 \(phone)") //電話番号 Optional("123-4567-8910")
print("誕生日 \(birthday)") //誕生日 Optional("20XX/XX/XX")

//アンラップ
//??演算子(nil合体演算子)
var phoneNumber:String = phone ?? "アンラップ失敗"

//アンラップ後に再度アクセス
print("電話番号 \(phoneNumber)") //電話番号 123-4567-8910
print(type(of: phoneNumber)) //String

Optional型変数 phone がアンラップ可能であれば アンラップした値変数 phoneNumber に代入します。
もしアンラップ失敗や、そもそも値が nil であれば右辺の “アンラップ失敗” という文字列を phoneNumber に代入します。

アンラップ前の phone の値には Optional と頭に付いていましたが、
アンラップ後の値を見るとOptional が取れて普通の String型 にアンラップされています。これで String型 の値として扱うことができるようになりました。
アンラップが成功した場合と失敗した場合の両方の処理を書くので、安全にアンラップする方法だと思います。

! 演算子 ( 強制アンラップ )

! 演算子を使ったアンラップの書式

Optional型の値!

Optional型の値 の後に ! を書くことで強制的にアンラップする事ができる演算子です。

~ ~ ~
//非必須項目に値を代入
phone = "123-4567-8910"
birthday = "20XX/XX/XX"

//アクセス
print("電話番号 \(phone)") //電話番号 Optional("123-4567-8910")
print("誕生日 \(birthday)") //誕生日 Optional("20XX/XX/XX")

//アンラップ
//!演算子(強制アンラップ)
var phoneNumber:String = phone!

//アンラップ後に再度アクセス
print("電話番号 \(phoneNumber)") //電話番号 123-4567-8910
print(type(of: phoneNumber)) //String

Optional型変数 phone の後に ! を書いて強制的にアンラップした値を 変数 phoneNumber に代入します。
アンラップ後のアクセスした結果を見るとアンラップされているのが分かります。

※ ただし ! 演算子( 強制アンラップ )は、 Optional型の値nil だった場合に強制アンラップするとプログラムがクラッシュしてしまいます。
値が nil なのに( アンラップの対象が無いのに )強制アンラップしているためです。
なので nil の可能性がある場合、値が入っているか分からない場合は使えません。
確実に値が入っていると分かっている場合に使います。

if-let文 ( オプショナルバインディング )

if-let文 を使ったアンラップの書式

if let 定数名 = Optional型の値 {
    アンラップに成功したらこの中の処理が実行
} else {
    アンラップ失敗したらこの中の処理が実行される
    else文を書いていない場合、このif-let文はスキップ
}

Optional型の値 がアンラップ可能であれば、アンラップした値を定数に代入し、{ } の中の処理が実行されます。
アンラップ失敗( 値が nil )であれば else文{ } の中の処理が実行されます。

else文 を書かなかった場合、アンラップ失敗( 値が nil )であれば if-let文 はスキップされます。

~ ~ ~
//非必須項目に値を代入
phone = "123-4567-8910"
birthday = "20XX/XX/XX"

//アクセス
print("電話番号 \(phone)") //電話番号 Optional("123-4567-8910")
print("誕生日 \(birthday)") //誕生日 Optional("20XX/XX/XX")

//アンラップ
//if-let文(オプショナルバインディング)
if let phoneNumber = phone {
    print(phoneNumber) //電話番号 123-4567-8910
    print(type(of: phoneNumber)) //String
} else {
    print("アンラップ失敗")
}

Optional型変数 phone がアンラップ可能であれば アンラップした値定数phoneNumber に代入し、{ } の中の処理を実行します。
アンラップ失敗( 値が nil )であれば else文{ } の中の処理が実行されます。
このアンラップ方法も アンラップが成功した場合と失敗した場合の両方の処理を書けるので、nil の値をアンラップしようとしてクラッシュするなどのエラー回避につながります。

エラーやクラッシュを回避するためにも、できるだけ強制アンラップは使わず、?? 演算子や if-let文 でアンラップした方が安全だと思います。

お疲れ様でした。
以上 Optional型 についてでした。

次回は while文 について書いていこうと思います。

実行環境

version
Xcode 14.2 (14C18)
Swift 5.2.4

公式ドキュメント

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/

【Swift】文字列型と文字列の型変換

文字列の型名はString型。
書き方は文字列として扱いたい値をダブルクォーテーション(“”)で囲みます。
データ型の記事で軽く触れてますが、今回は少し深掘って書いていこうと思います。文字列の結合-演算子(+)を使ってString型の値を結合することが出来ます。

前回は 数値型の演算 について記事を書きました。

今回は 文字列型と文字列の型変換 について書いていこうと思います。

文字列型とは

文字列の型名は String型
書き方は文字列として扱いたい値をダブルクォーテーション で囲みます。
データ型 の記事で軽く触れてますが、今回は少し深掘って書いていこうと思います。

String型の宣言例

var greeting:String = "Hello." //値をダブルクォーテーションで囲む
var gereting2 = "Swift!" //型推論

print(greeting) //Hello.
print(greeting2) //Swift!

型推論 についてはこちらの記事で紹介しています。

文字列の結合

算術演算子 + を使って String型 の値を結合することが出来ます。

算術演算子 についてはこちらの記事で紹介しています。

文字列の結合例

var greeting:String = "Hello."
var greeting2 = "Swift!"

print(greeting) //Hello.
print(greeting2) //Swift!

var greeting3 = greeting + greeting2 //+で結合
print(greeting3) //Hello.Swift!

//または
var name = "hoge"
var message = "こんにちは" + name + "です"
print(message) //こんにちはhogeです

文字列と文字列を結合することが出来たと思います。

エスケープシーケンス

上記の結合方法の他に、エスケープシーケンスを使って文字列の中に変数や定数を埋め込む事も出来ます。埋め込みたい箇所に \( ) と入力して、 ( ) の中に変数や定数を入れる事で埋め込む事が出来ます。

バックスラッシュは Optionキー を押しながら ¥マーク。(Mac)

var name = "hoge"
var message = "こんにちは" + name + "です"
print(message) //こんにちはhogeです

//エスケープシーケンスを使って変数を埋め込む
var message2 = "こんにちは\(name)です" //埋め込みたい箇所に\()を入力して()の中に変数や定数を入れます
print(message2) //こんにちはhogeです

この方法でもプラス演算子 + を使った結合と結果は同じになります。

特殊文字をエスケープする

例えばダブルクォーテーションやバックスラッシュを で囲うとエラーになります
ダブルクォーテーションやバックスラッシュなど特殊文字と言われる文字を文字列として扱いたい時や、改行したい時などはエスケープする事で出力することが出来ます。

バックスラッシュはOptionキーを押しながら¥マーク。(Mac)
特殊文字エスケープシーケンス
ダブルクォーテーション\”
シングルクォーテーション\’
バックスラッシュ\\
タブ文字\t
改行\n

エスケープシーケンスはこの他にもたくさんあります。

エスケープ例

print("123\"45") //123"45 (ダブルクォーテーション)
print("123\'45") //123'45 (シングルクォーテーション)
print("123\\45") //123\45 (バックスラッシュ)
print("123\t45") //123 45 (タブ文字)
print("123\n45") //123    (改行)
                 //45

文字列の型変換

String型Int型Float Double型 に変換する事が出来ます。また、逆に Int Float Double型String型 に変換することが出来ます。
型変換することをキャストとも言います。

型名() と書いて、( ) の中に変換したい変数や定数を入れると変換する事ができます。

文字列型から数値型へキャスト

String型 の変数を他の型にキャストする例

var a = "12345"
print(type(of: a)) //String

//StringをIntにキャスト
var b = Int(a) 
print(type(of: b)) //optional<Int>

//StringをFloatにキャスト
var c = Float(a)
print(type(of: c)) //Optional<Float>

//StringをDoubleにキャスト
var d = Double(a)
print(type(of: d)) //Optional<Double>

これで String型 を数値型に変換できましたが、実行結果を見てみると頭の所に optional と付いています。この optional と言うのは、変換しようとしている値は nil(空) の可能性がある場合に optional となります。
nil とは、値が入っていない空の状態を表しています。
nil じゃないよ!と明示するには、 アンラップ をする事で出来ますが、 optional型 や、アンラップ についてはまた今度記事を書こうと思います。とりあえずキャストは出来るので今回はこのまま進めます。

数値型から文字列型へキャスト

さっきの逆パターン

//IntをStringにキャスト
var e = 12345
print(type(of: e)) //Int
var f = String(e)
print(type(of: f)) //String

//DoubleをStringにキャスト
var g = 12.345
print(type(of: g)) //Double
var h = String(g)
print(type(of: h)) //String

これでキャスト出来たと思います。

String-escapeコードimg2

キャストする時の注意点

変換できなかった場合は nil が返される。
nil とは、値が入っていない空の状態を表しています。

nil が返される( 変換出来ない )例

var a = "123.45" //String
var b = Int(a)
print(b) //nil
print(type(of: b)) //Optional<Int>

これは、 String型 の変数を Int型 にキャストしようとしている例です。文字列に “123.45” と少数点が入っています。 Int型 は少数を扱えないのに Int型 にキャストしようとしているので、結果 nil が返されてしまいます。
文字列に小数点が含まれた値をキャストしたい場合は、 Float型 か、Double型 を指定しましょう。

var a = "123.45" //String
var b = Int(a)
print(b) //nil
print(type(of: b)) //Optional<Int>

//少数を扱えるFloat型にキャスト
var c = Float(a)
print(c) //Optional(123.45)
print(type(of: c)) //Optional<Float>

//数字の文字列じゃない場合、数値型に変換出来ず値はnilになります
var d = "abc"
var e = Int(d)
print(e) //nil
print(type(of: e)) //Optional<Int>
String-escapeコードimg

以上 文字列型と文字列の型変換 についてでした。

次回は 真理値型と比較演算子 について書いていこうと思います。

実行環境

version
Xcode 14.2 (14C18)
Swift 5.2.4

公式ドキュメント

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/