CHAPTER 04 オプショナル
今時の言語にはすべて搭載されている、ヌルポ対策機能。
オプショナル型と nil
Swift では null
でなく nil
で Objective-C には nil
も Null
も両方あるらしい。
null
許容型 Int
は Int?
とかく。これは Kotlin 等と同様。
オプショナル型の値を開示する
Int?
型を Int
型に変換するのに !
を使用する。確実に nil
が入っていないと予想できるときに使用する:
let year: Int? = Int("2020")
var remain: Int = year! - 2016 // ! が無いとコンパイルエラー
year! -= 2016 // このように代入も可能
if-let 文
オプショナル型の値が nil
ではなかった場合に処理をする、といった構文が if-let
文となる:
let year: Int? = Int("2020")
if let y = year {
print("あと \(y - 2014) 年") // y: Int として使える
} else {
print("エラー")
}
// 複数のオプショナルがともに nil でない場合は以下のように書く
if let sapporo = Int("1972"), nagano = Int("1998") {
print("\(nagano - sapporo) years.")
}
// where 句で更に条件を絞ることができる
if let sapporo = Int("1972"), nagano = Int("1998") where nagano > 1990 {
print("\(nagano - sapporo) years.")
}
guard 文
if-let
の逆、即ち条件を満たさない時に else
句の処理を行うことができる:
let stock = ["01", "2", "4", "05", "8", "q", "X"]
for str in stock {
guard let v = Int(str) else {
print(str + "??")
break
}
print(v, terminator:" ")
}
// 1 2 4 5 8 q??
nil 合体演算子
オプショナル型に対し ??
で値を取り出すことで nil
の場合にデフォルト値を使用するといったことができる:
opv ?? S // opv が nil なら S が使われる. opv != nil ? opv! : S と同様
有値オプショナル型
プログラムの前後関係から確実に nil
でない値が入っていると予想できる場合は Int?
でなく Int!
とすると使用する際に !
の開示が不要となる:
let year: Int! = Int("2020")
print("あと \(year - 2016) 年") // ! が不要
失敗のあるイニシャライザの定義
init
ではなく init?
を使用する。例えば init
への引数が防いで有効な構造体を生成できない時に nil
を返すようにするなど。
CHAPTER 05 基本的なデータ型
部分配列
配列のスライスはどうやるのかと思ったら範囲指定がそのまま使用できるようだ:
let stock = ["01", "2", "4", "05", "8", "q", "X"]
print(stock[1...4]) // ["2", "4", "05", "8"]
但し上記でスライスした配列は Array<String>
ではなく ArraySlice<String>
になり、添字が元のままの 1, 2, 3, 4 になる。
これを普通の 0 から始まる配列として使用したい場合は Array<String>
のイニシャライザで wrap する:
let subarray = [String](stock[1...4])
print(subarray[0]) // "2"
可変長引数
可変長引数指定は Java と一緒で Int...
のようにする。
但し Java と異なり引数の途中でも可変長引数にできる。
辞書の型宣言と初期値
辞書の型は [String: Int]
のように記述する。
var d: [String: Int] = [:] // 空の辞書代入
辞書へのアクセス
「辞書のキーが存在したらなにか処理をする」のようなものは if-let
文が使える:
var d = ["Swift": 2014, "Objective-C": 1983]
if let v = d["Swift"] { print(v) } // 2014
if let v = d["Ruby"] { print(v) } // 何も出力されない
集合の型宣言と初期値
配列リテラルが使用できるが型を明示的に指定しないといけない:
var s: Set<String> = ["フランダース", "フランドル", "フランシスカ"]
CHAPTER 06 パターン
キーワード付きのタプル
タプルにキーワードが付けられるというのは知らなかった:
let photo = (file: "tiger.jpg", width: 640, height: 800)
print(photo.0) // tiger.jpg
print(photo.file) // tiger.jpg
タプルを switch 文で使う
結構柔軟なことができるようだ:
switch day {
case (1, 1...5): // 範囲指定ができる
print("正月休み")
case (4, 29), (5, 2...6): // 更に条件を並べることができる
print("連休")
case (8, let d) where d > 10: // タプルの一部を使用することができるし where で条件を絞れる
print("8/\(d)は夏休みです")
default:
break
}
オプショナル型を switch 文で使う
オプショナル型を含むタプルに対し nil
でないことを条件とするには ?
を付けるようだ:
case let (name, age?) where age >= 18: // 開示した数値を代入
case let (name, (15...18)?): // 開示して区間指定
シンプルな列挙型
Java と似ているが case
接頭辞を付けるようだ:
enum Direction {
case Up, Down, Right, Left
}
値型の列挙型
列挙型に実体型 (raw value) を割り当てることができるらしい:
enum Direction: Int {
case Up = 0, Down, Right, Left // こう書くと 0, 1, 2, 3 となる
}
print(Direction.Right.rawValue) // 2
print(Direction(rawValue: 3)!) // Left
共用型の列挙型
イマイチ使い所がよく分からないが、それぞれの要素の型 (タプル) が異なる列挙型も定義できる:
enum WebColor {
case Name(String)
case Code(String)
case White, Black, Red
}
let background = WebColor.Name("indigo")
let tuiquoise = WebColor.Code("#04E0D0")
let textColor = WebColor.Black
if-case 文
switch
文だとパターンマッチングが使用できるが default
句を書かなければならず 1 つのパターンマッチングを行うだけだと冗長なので if-case
文という構文が用意されているようだ:
if case .card(let y, _) = t where y > 1200 { ...
for-in 文で case パターンを使う
for-in
でも case
が同様に使用できる。やはり switch
だと冗長なので代わりに使用できるようだ。
再帰的な列挙型
……こんな構文使うのか?と思うので、メモだけ。自分自身の型を再帰的に使用する場合は case
の前に indirect
を指定し特別扱いする。