Swift楽しいです。
参考書で1週間独学したので、学んだ構文などをまとめようと思います。
知識のアウトプットはもちろんですが、いつでも見返せるメモのような内容にしたいと思っています。
なので内容は適宜、加筆修正していくつもりです。
載せているコードは全てPlaygroundで動作を確かめながら書きました。
もし文法や解釈に間違いがありましたお手数ですがコメントでお教えいただけると幸いです...🙇♀️
私のプログラミング歴は一年に満たないくらいで、普段は主にPHPを書いています。
なので、この記事でも要所要所で引き合いにPHPを出したりしてます。
#Swiftの構文
##変数
var 変数名 = 初期値
// 宣言と初期値の代入
var name = "コーラ"
var price = 100
// 出力
print(name) // 結果 コーラ
print(price) // 結果 100
再代入による書き換えが可能。(初期値の型と同じ型に限る)
初期値によって変数自体がその型専用になるイメージ。
(例外として小数型に整数は代入可能)
var name = "コーラ"
name = 100 // 初期値と型が異なるのでこれはエラー
Swiftは初期値の代入時に型を自動的に判別してくれますが、以下のように明示的に指定する事も可能です。
var name: String = "コーラ"
var price: Int = 100
複数単語で成る変数名の場合は慣習的にキャメルケースで書きます。
var numberOfItems = 3
##定数
let 定数名 = 初期値
var
をlet
にしただけなので形はほぼ変数と同じ。
ただ変数と違い、再代入によって書き換える事は不可。
let tax = 1.1
tax = 0.8 // これはエラー
##配列
var 配列名 = [値, 値, 値]
let 配列名 = [値, 値, 値]
取り出すときは0から始まる添字(インデックス番号)を指定する。
定数にすると要素の変更が出来ない配列ができる。
同じ型の値しか扱うことができない
ので注意。
var drinks = ["コーラ", "コーヒー", "お酒"]
print(drinks[0]) // 結果 コーラ
###要素を書き換える
添字(インデックス番号)を指定して代入。
drinks[0] = "ファンタ"
print(drinks[0]) // 結果 ファンタ
###要素を追加する
要素を追加するときはappendメソッド
を使う。
末尾に追加される。
drinks.append("ミルク")
// ["コーラ", "コーヒー", "お酒", "ミルク"]
###要素を削除する
添字(インデックス番号)を指定してremoveメソッド
で削除。
drinks.remove(at: 3) // 添字の3番に当たるミルクを削除
// ["コーラ", "コーヒー", "お酒"]
##辞書
var 辞書名 = [キー: 値, キー: 値, キー: 値]
let 辞書名 = [キー: 値, キー: 値, キー: 値]
値に関連するキーをつけ、保持している内容を具体化し扱いやすくしています。
PHPの連想配列に近いですが、同じ型の値しか持つことができないので注意
です。
取り出すときはキー名を指定して呼び出します。
var items = ["name": "コーラ", "agency": "Coca-Cola"]
print(items["name"]) // 結果 コーラ
###要素を書き換える
キーを指定して再代入する。
items["name"] = "ファンタ"
print(items["name"]) // 結果 ファンタ
###要素を追加する
新しいキーを定義してそこに値をいれる。
items["headquartersLocation"] = "アメリカ"
print(items["headquartersLocation"]) // 結果 アメリカ
###要素を削除する
キーを指定してそこにnilを代入する。
items["headquartersLocation"] = nil
print(items["headquartersLocation"]) // 結果 存在しないのでエラー
##タプル
var 変数名 = (要素名: 値, 要素名: 値, 要素名: 値)
型の違いを気にしない
配列のような機能です。
値は以下のようにして呼び出します。
var drink = (name: "コーラ", price: 100, stock: 10)
print(drink.name) // 結果 コーラ
プロパティの呼び出しに酷似しています
。
構造体かと思ったらタプルだった、なんてことにならないよう注意したいです。
また、タプルは配列や辞書と異なり、
- 要素の追加
- 要素の削除
は出来ません。
##if文
if 条件式 {
処理
} else if 条件式 {
処理
} else {
処理
}
条件式がtrue
ならばブロック内の処理を実行します。
ほぼPHPと同じ。
var age = 20
if age >= 20 {
print("成人です")
} else if age >= 18 {
print("18歳以上です")
} else {
print("18歳未満です")
}
// 結果 成人です
##for文
for 定数名 in 範囲 {
処理
}
PHPのfor文よりシンプル!
for n in 1...5 {
print(n)
}
// 結果 1 2 3 4 5
in
の右側に書いた範囲の分だけブロック内でループが行われます。
繰り返しの範囲の指定は、
整数...整数
と書いて行います。
ちなみにブロック内で新たに変数を定義した際、その変数のスコープはそのブロック内に限られます。(ブロック外で定義したグローバルな変数はブロック内でも使用可能)
for n in 1...5 {
var name = "コーラ"
print(name) // 結果 コーラ
}
print(name) // 結果 ブロックの外(スコープ外)なのでエラー
スコープはPHPと違いますね。気をつけねば。
forを使って配列の反復処理を行う事も可能です。
var drinks = ["コーラ", "コーヒー", "お酒"]
for drink in drinks {
print(drink)
}
// 結果 コーラ コーヒー お酒
PHPのforeachのような動きをforでシンプルに行えるんですね。
##repeat文
repeat {
処理
} while 条件式
条件式がtrueの間、ブロック内の処理を繰り返し行います。
この特性を使って、乱数で100が出れば繰り返しを抜けるような処理を書いてみます。
var num = 0
repeat {
num = Int.random(in: 0..<101)
} while num != 100
print(num) // 結果 100
100以外の場合true、100ならばfalseになり繰り返しを抜けます。
##関数
func 関数名(ラベル名 引数名: 型) {
処理
}
###引数も戻り値もない関数
func sayHello() {
print("hello")
}
sayHello() // 結果 hello
###引数のある関数
引数は引数名:型
の形で渡します。
呼び出すときは、引数名:引数
の形。
func greeting(word: String) {
print("hello")
}
greeting(word: "hello") // 結果 hello
引数が複数あるときはこう。
// 定義
func greeting(word: String, name: String) {
print("\(word)、\(name)さん")
}
// 呼び出す
greeting(word: "hello", name: "くじら") // 結果 hello、くじらさん
###戻り値のある関数
戻り値の型を指定
して、処理結果をreturn
する。
func areaOfRectangle(width: Int, height: Int) -> Int{
let result = width * height
return result
}
var area = areaOfRectangle(width: 5, height: 6)
print(area) // 結果 30
###ラベル
関数の引数を自然な英文にすることができます。
長方形の面積を求める関数なら、
area of rectangle with width 5, height 6
となり、ある程度読める自然な英文にできます。
func areaOfRectangle(withWidth width: Int, height: Int) {
print(width * height)
}
areaOfRectangle(withWidth: 5, height: 6) // 結果 30
呼び出すときはラベルを使いますが、関数内の処理では引数名を使います。
ラベルを省略したとき、内部的には引数名と同名のラベルが自動で補完されています。
####ラベル アンダースコア(_)
関数の定義時にラベルにアンダースコアを指定すると、ラベルを指定した引数の受け渡しが出来なくなります。
func areaOfRectangle(_ width: Int, _ height: Int) {
print(width * height)
}
areaOfRectangle(5, 6) // 結果 30
不自然な英文に成るのを防ぐことができるとか。
##構造体
struct 構造体名 {
var プロパティ名 = 初期値
func メソッド名() {
処理
}
}
構造体名はアッパーキャメルで書きます。
以下は例。
struct Item {
var name = "コーラ"
var price = 100
func showName() {
print("これは\(name)です")
}
}
// インスタンスの作成
let item = Item()
// メソッドの呼び出し
item.showName() // 結果 これはコーラです
// プロパティの参照
print(item.price) // 結果 100
変数にインスタンスを作成する事なくメソッドを呼び出す事も可能。
Item().showName() // 結果 これはコーラです
プロパティの値の書き換えは再代入で行う。
item.name = "ファンタ"
print(item.name) // 結果 ファンタ
###プロパティ
####ストアドプロパティ
値を保持する為のプロパティ
struct Item {
var name = "コーラ" // ストアドプロパティ
// 略
}
let item = Item()
print(item.name) // 結果 コーラ
####コンピューテッドプロパティ
値を計算する為のプロパティ。
以下のような注意点があります。
- 値が可変である為、変数(var)として定義する必要がある
- 型の指定が必須
struct Item {
var price = 100
// 税込価格を計算するコンピューテッドプロパティ
var priceWithTax:Int {
let result = price * 1.1
return result
}
// 略
}
let item = Item()
print(item.priceWithTax) // 結果 110
内部では関数的な処理が行われているのですが、呼び出しの部分だけ見るとまるでストアドプロパティであるかのように参照することが出来ます。
ちなみに上のコンピューテッドプロパティは以下のようにシンプルに書くことが出来ます。
var priceWithTax:Int {
price * 1.1
}
これはSwiftの、
ブロック内({ })の式が一つしかない場合、returnを省略することが出来る
というルールを利用した書き方です。
中間変数resultに計算結果を代入する処理を省略し、ブロック内のコードを一行して、上記のルールに則ってreturnを省略したというわけです。
この書き方かなりシンプルで好きです。
###イニシャライズ
インスタンス作成時に構造体の初期処理を行うことです。
PHPでいうところのコンストラクタ。
struct Item {
var name: String
var price: Int
init(name: String, price: Int) {
self.name = name
self.price = price
}
// 略
}
let item = Item(name: "コーラ", price: 100)
print(item.name) //結果 コーラ
インスタンス作成時の引数は以下のようになっていますが、
let item = Item(ラベル名:引数, ラベル名:引数,)
注意するべき点として、このとき指定しているのでは引数名ではなくラベル名だということです。
先ほどのコードは呼び出しの際に引数名を指定しているように見えますが、
let item = Item(name: "コーラ", price: 100)
これはSwiftに以下のようなルールがある為です。
ラベルを省略すると引数名と同じ名前のラベルが自動で補完される
先ほどのコードはinit()でラベルを省略しているのでこのルールが適応されているというわけです。
###プロトコル
protocol プロトコル名 {
var ストアドプロパティ名: 型名 { get set }
var コンピューテッドプロパティ名: 型名 { get }
func メソッド名()
}
構造体に実装しなければならないプロパティやメソッドの約束事を決める機能です。
あるプロトコルを適合させた構造体は、そのプロトコルに書かれているプロパティやメソッドを実装することが義務付けられます。
PHPでいうところのインターフェイスだと思います。
エナジードリンクを例に実際に書いてみます。
// プロトコルの定義
protocol energyDrinkProtocol {
var amountOfArginine: Int { get set } // 保有するアルギニンの量を表すプロパティ
func replenishEnergy() // エネルギーを補充するメソッド
}
構造体に適合させてみます。
struct monster: energyDrinkProtocol {
var amountOfArginine = 125
var amountOfCaffeine = 40
func replenishEnergy() {
print("元気百倍!!")
}
func stimulateTheBrain() {
print("脳が活性化したよ!!")
}
}
energyDrinkProtocolに従い、monster構造体はamountOfArginineプロパティとreplenishEnergy()メソッドを持っておりプロトコルの約束通りの実装です。なのでエラーは出ません。
これがもし、
struct monster: energyDrinkProtocol {
var amountOfCaffeine = 40
func stimulateTheBrain() {
print("脳が活性化したよ!!")
}
}
のようになっていると、プロトコルとの約束事に反する為エラーが出ます。
まとめると、プロトコルは構造体の仕様書のようなもので、構造体の実装内容をある程度保証する役割があります
。
##クラス
class クラス名 {
var プロパティ名 = 初期値
func メソッド名() {
処理
}
}
見ての通り、クラスの構文は構造体とほぼ同じです。
struct
をclass
に変更しただけ!
struct Item {
var name = "コーラ"
var price = 100
func showName() {
print("これは\(name)です")
}
}
class Item {
var name = "コーラ"
var price = 100
func showName() {
print("これは\(name)です")
}
}
見た目は似たような子達ですが、インスタンスの値の扱い方が異なります。
それぞれ、値型
と参照型
に分類でき、
- 構造体は値型
- クラスは参照型
となっています。
まず値型
は以下のような動きになります。
struct Item {
var name = "コーラ"
var price = 100
func showName() {
print("これは\(name)です")
}
}
var itemA = Item()
var itemB = itemA
itemA.name = コーヒー
itemA.showName() // 結果 これはコーヒーです
itemB.showName() // 結果 これはコーラです
インスタンス作成後、itemAのnameプロパティをコーヒーに書き換えました。
その後それぞれメソッドを呼び出してみると、nameプロパティがコーヒーになっているのは直接書き換えたitemAの方だけだということがわかります。
それぞれのインスタンスは独立していて別物なのだと考えることができます。
これに対して参照型
では以下のような動きになります。
class Item {
var name = "コーラ"
var price = 100
func showName()
print("これは\(name)です")
}
}
var itemA = Item()
var itemB = itemA
itemA.name = コーヒー
itemA.showName() // 結果 これはコーヒーです
itemB.showName() // 結果 これはコーヒーです
書き換えたのはitemAのnameプロパティだけのはずが、itemBにまで影響が出ています。
これが参照型です。
影響範囲が広くて使うのが少し怖い感じがします。
慣れないうちは構造体で……。
###継承
class 子クラス名: 親クラス名 {
}
用語として、
- 継承する方が子クラス
- 継承される方が親クラス
です。
継承をすることで親クラスのプロパティやメソッドを子クラスで使用できるようになります。
これにより複数のクラスで重複するコードは、親クラスで一括で管理できるようになりコード量を減らせ、また後に修正があった際も親クラスのみの修正で済むようになります。
クラス名は構造体と同様にアッパーキャメルで書きます。
エナジードリンクを例に書いてみます。
まず継承をせずにMonsterクラスとRedBullクラスを定義します。
class Monster {
var energy = 0
func drink {
energy += 10
}
}
class RedBull {
var energy = 0
func drink {
energy += 5
}
}
この二つのクラスを見ると、energyプロパティが重複しているのがわかります。
これを継承を使って解決します。
// 親クラス
class EnergyDrink {
var energy = 0
}
class Monster: EnergyDrink {
func drink() {
energy += 10
}
}
class RedBull: EnergyDrink {
func drink() {
energy += 5
}
}
それぞれのクラスで定義していたenergyプロパティが、親クラスで一度定義すればいいだけになりました。
メソッドも同様に、
// 親クラス
class EnergyDrink {
var energy = 0
func stimulateTheBrain() {
print("脳が活性化したよ!!")
}
}
class Monster: EnergyDrink {
func drink() {
energy += 10
}
}
class RedBull: EnergyDrink {
func drink() {
energy += 5
}
}
var redBull = RedBull()
var monster = Monster()
redBull.stimulateTheBrain() // 結果 脳が活性化したよ!!
monster.stimulateTheBrain() // 結果 脳が活性化したよ!!
と出来ます。
注意点は、
- 継承できる親クラスは一つまで
- 親クラスが継承している親クラスも子クラスに継承される
です。
##列挙体
enum 列挙体名 {
case 値
case 値
case 値
case 値
}
独自の型を定義する機能です。
決まり切った値の内から指定させ、その値によって動作を変えるような処理を書くときに有効的です。
意図しない値が渡されるのを防ぐことができます。
enum zodiac {
case rat
case ox
case tiger
case rabbit
// 略
}
// 値を取得
var thisYear = zodiac.rat
// 同じ列挙体で初期化済みの変数を書き換えるときは、列挙体名を省略できる
this.year = .ox
上記の例だと、列挙体zodiac
には十二支が定義されており、誤ってここに猫(cat)が入るようなことを防ぐことができます。
個人的な所感としては、列挙体は複数の定数を名前をつけて管理することで、可読性を上げることができるのがメリット
なのだと思います。
##比較演算子
初めてqiitaでテーブル使いました...。
比較演算子 | 意味 |
---|---|
== | 左辺と右辺は等しい |
!= | 左辺と右辺は等しくない |
< | 左辺は右辺より小さい |
> | 左辺は右辺より大きい |
<= | 左辺は右辺以下 |
>= | 左辺は右辺以上 |
##型
参考者で学んだ基本的な部分の紹介になります。
また、現段階では把握しきれていないので扱いませんが、Swiftの型は全て構造体で出来ており、各型が独自のプロパティやメソッドを持っています。
###文字列型 String
文字列はダブルクォートで囲みます。
print("hello")
print("1")
####文字列補完
"\(変数名)"
文字列の中で変数を展開することができる機能。
var name = "くじら"
print("こんにちは、\(name)") //結果 こんにちは、くじら
// 文字列に整数を組み込む事もできる
var age = 23
print("くじらは\(age)歳です") //結果 くじらは23歳です
###整数型 Int
ダブルクォートで囲むと数値(整数型)ではなく、数字(文字列型)と見做されてしまうので注意。
print(1) // これは数値(Int)
print("1") // これは数字(String)
###小数型 Double
小数点以下の有無で整数と区別されます。
print(1.1)
###配列型 Array
// 空の配列を定義
var ar = [String]()
var ar = ["きのこ", "卵"]
###ブール型 Bool
print(true)
print(false)
print(100 == 100) // true
print(100 == 10) // false
###オプショナル型
var 変数名:型? = 初期値
型の後ろに?
をつけることで、nil(=何もない)を取り得る変数であるという宣言ができます。
var price: Int? = nil
上記はInt(整数型)
の宣言をした変数に?
がついています。
これにより、本来整数しか代入できないはずの変数
を、整数とnilをも扱うことのできる変数
としています。
var price: Int?
print(price) // 結果 nil
price = 100
print(price!) // 結果 100
オプショナル型である変数は初期値を代入しない場合、自動的にnil
がセットされます。
オプショナル型の変数からnilではない型の値を呼び出すとき
は変数名の後に!
をつけてあげます。
var price: Int? = 100
print(price) // 結果 Optional(100) (Optinal)
print(price!) // 結果 100(Integer)
!
をつけない場合、オプショナル型の値となってしまう為、下記のような計算が出来ません。
print(price + 100) // オプショナル型と整数型で計算しようとしているのでエラー
さらに注意しなければいけないのは、
nilが代入されている変数に!
をつけて呼び出すとエラーがでる
という点です。
つまり、!は変数の値がnilでないことを確約できる時のみ使用できる
ということで、
逆に言えば、!がついていればnilが入っていない変数なのだなと理解できる為、読む側としては便利です。
※オプショナルチェーンという機能については後日ここに追記します。
###型としてのプロトコル
var 変数名: プロトコル名 = 構造体名
プロトコルを適合させた構造体しか代入できない。
#一言
Swiftは型に関してかなりしっかりしているなーと感じました。
普段使いのPHPは型の概念が緩いので書いていて新鮮です。
#今後参考にするつもり・・・
一度は公式のドキュメントもしっかり読まないとなーと思ってます。(英語...)
公式 A Swift Tour