趣味でIOSアプリ開発をかじっていた自分が、改めてSwiftを勉強し始めた際に、曖昧に理解していたところや知らなかったところをメモしています。
参考文献
この記事は以下の書籍の情報を参考にして執筆しました。
switch文でwhere節を使う
func trashDate(weekly: Int, weekday: String){
let week = (weekly, weekday) // タプル型
switch week {
case (_, "月曜日"):
print("燃えるゴミの日")
case (let i, "木曜日") where i == 1 || i == 3 : // where節の条件に一致する場合処理を実行
print("燃えないごみの日")
case let (i, j):
print("第\(i)週 \(j)")
}
}
trashDate(weekly: 4, weekday: "月曜日") // 燃えるゴミの日
trashDate(weekly: 2, weekday: "木曜日") // 第2週 木曜日
trashDate(weekly: 1, weekday: "木曜日") // 燃えないごみの日
trashDate(weekly: 99, weekday: "hoge") // 第99週 hoge
switch文でオプショナル型を使う
func ageConfirmation(people: (String, Int?)) {
switch people {
case let (name, age?) where age >= 20:
print("\(name),成人済み")
case let (name, age?) where age < 20 && age >= 0:
print("\(name),未成年")
case (let name, nil) :
print("\(name),年齢不詳")
default:
break
}
}
ageConfirmation(people: ("hoge", 20)) //hoge,成人済み
ageConfirmation(people: ("fuga", 8)) //fuga,未成年
ageConfirmation(people: ("foo", nil)) //foo,年齢不詳
ageConfirmation(people: ("bar", -8))
列挙型のメソッド
enum Coin {
case front, back
func reverse() -> Coin{
switch self {
case .front:
return .back
case .back:
return .front
}
}
}
let coin = Coin.back
print(coin) // back
print(coin.reverse()) // front
値型の列挙型
enum Coin: Int {
case front = 0, back //backは1になる
func reverse() -> Coin{
switch self {
case .front:
return .back
case .back:
return .front
}
}
}
let coin = Coin.back
print(coin) // back
print(coin.rawValue) // 1
print(coin.reverse().rawValue) //0
列挙型のケースを全て含むコレクション
enum Coin: Int, CaseIterable {
case front = 0, back //backは1になる
}
print(Coin.allCases) // [CodeTest.Coin.front, CodeTest.Coin.back]
for elm in Coin.allCases{
print(elm) // front back
}
if-case文
let p = Payment.クレジット(120, true)
// pがクレジットカードかを知りたい
if p == .クレジット{ // error
print("クレカ")
}
// switch文でも書けるが少し面倒
switch p {
case .クレジット:
print("クレカ")
default:
break
}
// if-caseを使う
if case .クレジット = p {
print("クレカ")
}
for-in文でcaseパターンを使う場合
enum Payment {
case クレジット(_ 残高:Int, _ 使用可能: Bool)
case アプリ(_ 残高: Int, _ 還元率: Double = 0.02)
case 現金
}
let paylist: [Payment] = [.クレジット(120, true), .アプリ(1120),
.現金, .クレジット(12000, true), .クレジット(99999, false),
.クレジット(1200, true)]
// 1100円以上の残高があり、使用可能なクレジットカードを取り出す
for case let .クレジット(money, b) in paylist where b == true && money >= 1100 {
print(money)
}
// このように書くのと同じ
for t in paylist {
switch t {
case let .クレジット(money, b):
if b == true && money >= 1100{
print(money)
}
default:
break
}
}
再帰的な列挙型
// 再帰的に呼び出すcaseの前にindirectをつける
enum メッセージ : CustomStringConvertible{ // プロトコルを採用
case 文書(_ 差出人: String, _ 文章: String)
case 添付(_ 差出人: String, _ データ: String)
indirect case 転送(_ 差出人: String, メッセージ)
var description: String{
switch self {
case let .文書(from, str):
return from + " : " + str
case let .添付(from, data):
return from + " : " + data
case let .転送(from, message):
return from + " : " + " <- \(message)"
}
}
}
// XcodeでFIXしたとき
indirect enum メッセージ : CustomStringConvertible{ // プロトコルを採用
case 文書(_ 差出人: String, _ 文章: String)
case 添付(_ 差出人: String, _ データ: String)
case 転送(_ 差出人: String, メッセージ)
var description: String{
switch self {
case let .文書(from, str):
return from + " : " + str
case let .添付(from, data):
return from + " : " + data
case let .転送(from, message):
return from + " : " + " <- \(message)"
}
}
}
let m1 = メッセージ.文書("hoge", "Hello")
let m2 = メッセージ.転送("fuga", m1)
let m3 = メッセージ.転送("foo", m2)
print(m1) // hoge : Hello
print(m2) // fuga : <- hoge : Hello
print(m3) // foo : <- fuga : <- hoge : Hello
パターンマッチ演算子
Swiftのパターンマッチ :
スクリプト言語などが持っている文字列と正規表現のマッチングではない。
どの構造が何に対応するかに関してのルールに基づくデータ構造の対応づけ
~= : パターンマッチ演算子
let hoge = Coin.front
print(hoge ~= Coin.front) // true
パターンマッチ演算子のルールを追加
ただし、パターンマッチ演算子の新たな定義を追加すると、switchやif-case文の挙動に直接影響するので必要性について考えること。
enum Coin: Int {
case front, back
func reverse() -> Coin{
switch self {
case .front:
return .back
case .back:
return .front
}
}
}
// パターンマッチ演算子の定義を追加
func ~= (c: Coin, s: String) -> Bool{
"\(c)" == s
}
let coin = Coin.front
print(coin ~= "front") // true
print(coin.reverse() ~= "front") // false