【Swift】基本構文を復習!タプルや変数の使い方、型の注意点
この記事からわかること
- Swiftの基本構文
- タプルとは?
- 変数の使い方
- 厳格な値の型を扱う上での注意点
- タプルと配列の違い
- オプショナル型とは?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
Swiftを学び出した私ですが、他のプログラミング言語と構文や変数の使い方が混じらないように整理しながらまとめていきたいと思います。
Swiftの変数の宣言方法
変数の初期値を宣言する
var user = "ame"
変数の型のみ宣言する
var user:String
変数の型と初期値を宣言する
var user:String = "ame"
Swiftでは宣言された型とは異なる型の値を入れようとするとエラーになります。
var user:String = "ame"
user = 2
error: cannot assign value of type 'Int' to type 'String'
また型宣言をしていない変数は初期値に格納された値の型が自動的に宣言されます。これを型推論と呼びます。
var user = "ame" // この時点で String型になる
user = 2
error: cannot assign value of type 'Int' to type 'String'
型変換(キャスト)
変数から値を取り出すときにデフォルトの型とは別の型に変換する(キャスト)こともできます。キャストするには型名(変数)
の形式で記述します。
var num:Int
num = 20
var str = String(num) // "20"
数値型から文字列型への変換は容易に行えますが、文字列から数値へ変換する場合は注意が必要です。数値に変換できない文字列を渡されてしまうとエラーや予期せぬ挙動を起こす原因になってしまうのでその時は関数の中に使えるguard 〜 else
構文が役に立ちます。
var str:String
str = "3" // "swift"などが渡される可能性もある場合
func numCheck () -> Bool{
guard Int(str) != nil else {
// 文字列の場合
return false
}
// 数値の場合
return true
}
if(numCheck()){
print("数値だよ")
}else{
print("文字列だよ")
}
Int(str)
で型変換に成功した時のみ数値に変換された処理を実行できるようになります。この構文はオプショナルバインディング(後述のOptional型をアンラップする)の方法の1つです。
Swiftの変数の型の種類
データ型
型名 | 概要 | 例 |
---|---|---|
String | 文字列型 | "swift" |
Character | 文字型(1文字) | "s" |
Int | 整数型※ | 23 |
Double | 浮動小数点数型 | 5.3 |
Bool | 真偽型 | true |
Character型は1文字1文字に対する型であり、String型はCharacter型の集合です。
※Int(整数型)に関しては「データ長」と「符号の有無」によってさらに型名が分かれています。
符号有り | 符号無し | データ長 |
---|---|---|
Int | UInt | 環境によって変化(32ビット〜64ビット) |
Int8 | UInt8 | 8ビット |
Int16 | UInt16 | 16ビット |
Int32 | UInt32 | 32ビット |
Int64 | UInt64 | 64ビット |
データ長を指定すると格納できる数値の大きさに制限がかかり、超えてしまうとオーバーフローが発生しパースエラーになります。符号無し(U付き)UInt○
であれば「2の○乗」の値がMAX値になります。(例:UInt8 = 2の8乗 = MAX:256)
var score:Int8 = 127 // OK
var score:Int8 = 128
error: integer literal '128' overflows when stored into 'Int8'
コレクション型
型名 | 概要 | 例 |
---|---|---|
Array | 配列型 | ["ame","kasa"] |
Dictionary | 辞書型 | ["name":"ame","age":2] |
Set | Set型 | ["ame","kasa"] |
配列や辞書型(連想配列)などはコレクション型と呼ばれます。Set型は記述方法は配列と同じですが、順序がなく重複のないデータを扱うための型です。なので重複のある配列をSet型で定義すると重複値は自動で削除されてしまいます。
var student:Set = ["ame","ame","kasa"]
print(student) // ["ame","kasa"]
computedプロパティ
computedプロパティ(コンピューテッドプロパティ)とは計算された値を返す変数です。宣言方法は特に変わりませんがreturn
を使って値を返す書式になります。クロージャ内に記述するステートメント(コード)が1行の場合はreturn
自体を省略することも可能です。
var num:Int {
return 5
}
print(num) // 5
computedプロパティは中に式や処理埋め込むことが可能です。その計算結果や処理結果をreturnで返します。
var num:Int {
let result = 2 + 5
return result
}
上記の構文は省略された形で省略していない形で表すと下記のようになります。computedプロパティの正しい構文はget{}
と後述するset{}
が用意されています。get{}
の中でreturn
した値が変数を参照した時に取得できる値になります。get{}
のみを記述した場合は読み取り専用の変数になりget{}
を省略することができます。
var num:Int {
get {
let result = 2 + 5
return result
}
}
set{}
を使って、値を渡して任意の計算を施した結果を返すことも可能です。例えば下記はsale
を参照すると50円割引された値を返し、sale
に値を格納すると割引されていない値を返します。
var price = 200
var sale:Int {
get {
price - 50
}
set (num) {
price = num + 50
}
}
print(price) // 200 割引前
print(sale) // 150 割引後 get{}が実行
sale = 500 // 割引後 set{}が実行
print(price) // 550 割引前
// priceと saleは常に割引の差がある状態の値が格納
定数を宣言する
定数とは宣言後値を変えられない値のことです。変数はvar
でしたが、定数はlet
を使って宣言します。
let user = "ame"
宣言後に値を書き換えようとするとパースエラーになります。
let user = "ame"
user = "kasa" // 書き換えを試みる
error: cannot assign to value: 'user' is a 'let' constant
変数同士や変数と文字を結合する
変数同士の結合(String)
var greeting = "Hello"
var user = "ame"
let result = greeting + user // "Helloame"
変数と文字列の結合(String)
var greeting = "Hello"
let result = greeting + "太郎" // "Hello太郎"
変数(Int)と文字列の結合
数値と文字列を結合させる場合はそのまま結合するとパースエラーになってしまいます。
var score:Int = 80
let result = "点数は" + score + "です"
error: cannot convert value of type 'Int' to expected argument type 'String'
その場合はInt型をString型に型変換(キャスト)して結合します。その場合はString(値)
で変換可能です。
var score:Int = 80
let result = "点数は" + String(score) + "です"
変数を文字列に埋め込む
変数の結合を意識せずとも\(変数名)
を使えば文字列の中に埋め込むこともできます。この場合は変数の型を意識することなく結合することが可能です。
var user = "ame"
let result = "こんにちは\(user)さん"
改行を含んだ文字列を格納する
"""〜"""
で文字列を囲むとその中に改行を含んだ見た目通りの文字列を格納することができます。"〜"
でも\n
(改行コード)を使えば改行を含んだ文字列を作成することができます。
var str = """
こんにちは。
これは改行を含んだ
文字列です。
"""
var str = "こんにちは\nこれは改行を含んだ\n文字列です"
タプルとは?使い方や注意点
Swiftにはタプル(tuple)という配列のような複数値を保持できる変数が存在します。(〜)
を使ってタプルは格納します。
var user = ("ame",25,"Swift")
型宣言とエラー
var user:(String,Int,String) = ("ame",25,"Swift")
また型宣言をしていない場合は型推論で型が決定します。型の違う値を入れようとしたり、タプルの個数に合わない値を入れようとするとパースエラーになります。
var user = ("ame",25,"Swift")
// 型違いを格納
user = ("ame",25,175) //error:cannot assign value of type '(String, Int, Int)' to type '(String, Int, String)'
// 個数の合わないタプルを格納
user = ("kasa",18) //error:cannot assign value of type '(String, Int)' to type '(String, Int, String)'
タプルの要素を取得する
タプルの中の要素を取得するには要素番号(0から始まるインデックス)を使って個別に取得することができます。
var user = ("ame",25,"Swift")
print(user.0) // ame
print(user.1) // 25
タプルの要素にラベルをつけて取得する
タプル宣言時に要素のラベルをつけることで変数.ラベル名
でアクセスすることができるようになります。
var user = (name:"ame",age:25,language:"Swift")
print(user.name) // ame
print(user.language) // Swift
// 要素ごとに値を変更することも可能
user.name = "kasa"
print(user.name) // kasa
タプルから値を取り出す(アンパック)
タプルの中から値を取り出すことをアンパック(展開)と言います。アンパックするには一度タプルを受ける変数を用意します。受け取りたくない値は_
を使って個数調整を行うことで個数違いによるエラーを防ぐことができます。
var user = ("ame",25,"Swift")
var (name,age,_) = user
let result = "名前は" + name + "歳は" + String(age) + "です。"
Swiftの配列
タプルと少し似ていますがSwiftでは配列も扱うことができます。型宣言をしない場合は型推論で型が決定します。
var language:[String]
language = ["HTML","CSS","JavaScript","PHP","Swift"]
// 1行で宣言と初期値の設定も可能
var language:[String] = ["HTML","CSS","JavaScript","PHP","Swift"]
配列の要素を取得する
配列の中の要素には配列名[要素番号]
でアクセスできます。
var language = ["HTML","CSS","JavaScript","PHP","Swift"]
print(language[0]) // HTML
language[0] = "HTML5"
print(language[0]) // HTML5
配列の要素にレンジを持たせてアクセスする
配列の要素には要素番号にレンジ(幅)を持たせて参照することもできます。その場合は要素番号...要素番号
の形式でレンジを持たせることができます。
var language = ["HTML","CSS","JavaScript","PHP","Swift"]
print(language[0...3]) // ["HTML", "CSS", "JavaScript", "PHP"]
// 要素の個数が合わなくても上書き可能
language[0...3] = ["HTML5"]
print(language) // ["HTML5", "Swift"]
配列に要素を追加する
最初に宣言した要素数に加えて追加したい場合は配列.append(要素)
を使って追加していきます。
var language = ["HTML","CSS","JavaScript","PHP","Swift"]
language.append("C++")
print(language) // ["HTML", "CSS", "JavaScript", "PHP", "Swift", "C++"]
配列に複数の要素を追加する
var language = ["HTML","CSS","JavaScript","PHP","Swift"]
language.append(contentsOf:["C++","SQL"])
print(language) // ["HTML", "CSS", "JavaScript", "PHP", "Swift", "C++", "SQL"]
連想配列の作り方とprintエラー
配列にもラベルをつけて連想配列(辞書型)にすることも可能です。しかしprint()
を使う場合は「Expression implicitly coerced from 'String?' to 'Any'」と言ったWarning(警告)が出てしまうので??
(NULL合体演算子)でエスケープできます。
var language = ["a":"HTML","b":"CSS"]
let result = language["a"] // HTML
print(result) // Expression implicitly coerced from 'String?' to 'Any'
// ↓これで解決
print(result ?? "")
タプルと配列の違い
タプルと配列は似ている部分が多く混同しがちです。両者の違いを見比べてみましょう。
タプル | 配列 | |
---|---|---|
囲い文字 | ( 〜 ) | [ 〜 ] |
ラベルの付け方 | (name:"ame") | ["name":"ame"] |
要素の取り出し方 | tuple.0 | array[0] |
型宣言 | tuple:(String,Int) | array:[String] |
両者を扱う上での違いとポイント
- タプルは複数の型を保持できる/配列はできない
- for-in文でタプルは回せない/配列はできる
- 要素インデックスは両者とも0から始まる
// 問題なし
var language = ["HTML","CSS"]
for lang in language {
print(lang)
}
// error: for-in loop requires '(String, String)' to conform to 'Sequence'
var language = ("HTML","CSS")
for lang in language {
print(lang)
}
Optional(オプショナル)型とnil
Optional(オプショナル)型とは空の状態(nil)を格納できる変数の型式です。Swiftでは値が空であることに厳格で通常ではnil
を参照しようとするとエラーを起こしてしまいます。
nilを通常の変数に格納する
通常の変数にnil
を格納しようとするとエラーになります。
var bird: String
bird = nil // expression failed to parse : nil' cannot be assigned to type 'String'
nilを許容する変数の宣言方法
型名の後に?
をつけるとnil
を許容するOptional型として宣言されます。通常の変数通り宣言した型に準じた値を格納することもできますが、出力する場合はOptional(値)
となってしまいます。
var bird: String?
bird = nil
bird = "アマツバメ"
print(bird) // Optional("アマツバメ")
// 警告:Expression implicitly coerced from 'String?' to 'Any'
これは変数bird
がOptional型になったことで「nilかもしれない値(オプショナルバリュー)」になっているからです。そのまま使用するとエラーになる可能性があるから注意してねということですね!
アンラップ
オプショナルバリューを出力する際はOptional型を解除(アンラップ)しないといけません。変数の後ろに!
をつけるとその値を強制的にアンラップすることができます。
var bird: String?
bird = "アマツバメ"
print(bird!) // アマツバメ
??演算子
??
演算子を使用するとnil
だった場合に代わりの値を出力することができます。
ar bird: String?
print(bird ?? "アマツバメ")
オプショナルバインディング
オプショナルバリュー(nilかもしれない値)をエラーを起こさないように安全にアンラップする方法がオプショナルバインディングです。種類はいくつかありますが、値がnil
かどうかを識別し処理を分岐させるという点は同じです。
guard〜else構文
guard〜else構文
は関数の中でオプショナルバリューを扱う時に使用できるオプショナルバインディングです。変数の中に値を格納する際にnil
かどうかをチェックし処理を分岐させます。nil
だった場合はその時点で関数の処理を中断させ、nil
でない時は値をアンラップして格納したあと後続の処理を続けます。
guard let 変数 = オプショナルバリュー else {
// nilだった場合の処理
return // ここで処理が中断される
}
// nilではなかった場合の処理
変数の宣言はlet
でもvar
でもOKですが、後続の処理で変数自体を使わない場合はのValue '変数' was defined but never used; consider replacing with boolean test
ような警告が出てしまうのでnilかどうかを確かめる構文に変えておきます。
guard オプショナルバリュー != nil else {
// nilだった場合の処理
return
}
if〜else構文
guard文はnil
だった場合に処理を中断させましたがif分のオプショナルバインディングは主に後続の処理を分岐させる場合に使用されます。基本的な使い方はguard文と同じです。
if let 変数 = オプショナルバリュー {
// nilではなかった場合の処理
} else {
// nilだった場合の処理
}
関数
Swiftでの関数はfunc
で定義します。
func 関数名 () {
処理
}
定義すれば関数名()
と記述するだけで特定の処理を実行させることができます。
func printFoo() {
print("foo")
}
printFoo() // foo
関数を実行して戻り値を受け取ることも可能です。その際は戻り値の型を明示的に指定しないとエラー(Unexpected non-void return value in void function.Did you mean to add a return type?
)になります。
func 関数 () -> 戻り値の型{
return 戻り値
}
func backFoo () -> String{
return "foo"
}
print(backFoo()) // foo
関数に引数を渡す
関数に外から値(引数)を渡すこともできます。定義するときに引数名とその型を、呼び出す時には引数名:値
の形式で指定しないとエラーになってしまいます。
func printHello (user : String) {
print("こんにちは\(user)さん")
}
printHello(user :"ame") // こんにちはameさん
引数に初期値を指定する
引数には初期値を指定することもできます。 初期値は上書きすることもできるので、設定していれば外部から値を渡さない場合の処理と外部から受け取る2つのパターンに対応した関数にすることができます。
func printHello (user : String = "ame") {
print("こんにちは\(user)さん")
}
printHello() // こんにちはameさん
printHello(user :"kasa") // こんにちはkasaさん
呼び出し時に引数名を省略する
引数名の定義時に_
をつけると呼び出し時の引数名を省略できます。
func printHello (_ user : String) {
print("こんにちは\(user)さん")
}
printHello("ame") // こんにちはameさん
呼び出し時に引数名を別名にする
外部引数名 引数名 : 型
の形式で定義すると呼び出し時の引数名を任意のものに変更することができます。
func printHello (customer user : String) {
print("こんにちは\(user)さん")
}
printHello(customer : "ame") // こんにちはameさん
おすすめ記事:【Swift】構造体(struct)とは?プロトコルやイニシャライザの使い方
おすすめ記事:【SwiftUI】modifier(モディファイア)とは?種類や指定方法
私がSwift UI学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。