Subscripts

昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/Subscripts.html を読む。

  • クラス、構造体、列挙型は subscript を定義できる
  • subscript(index: Int) -> String { get{ return …} set(newValue){〜} }
    • setのデフォルトパラメータ名はnewValue
  • subscript(index: Int) -> String { return …} 読み取り専用
  • 配列[index] 辞書[key] のようにアクセスできる
  • 一つの型に複数 subscript を定義できる(オーバーロード)
  • 添字形式 [] を使っている文脈で型推論されて適切なやつが選ばれる
  • 入力パラメータの数はいくつでも。パラメータの型は何でも
  • 返り値の型はなんでも
  • パラメータは可変引数にできる
  • inout パラメータは使えない。デフォルトパラメータ値はできない

Methods

昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/Methods.html を読む。

  • 構造体と列挙型にメソッドを定義できることがCやObjective-Cとの大きな違い
  • どの型のインスタンスにも self と呼ばれる暗黙のプロパティがある
  • 構造体と列挙型ではmutating キーワードを func の前に書いてオプトインする
  • 構造体と列挙型ではmutatingインスタンスメソッドはletしたインスタンスでは呼べない
  • mutatingインスタンスメソッドでself書き換え self = Point(x: x + deltaX, y: y + deltaY)
  • 型メソッドは要するにObjective-Cでのクラスメソッドのこと
  • 型メソッドでのselfは型そのものを参照する
  • 返り値を無視しても間違いじゃないメソッドには @discardableResult 属性

self はプロパティやったんや… this ポインタのキーワードが違うだけやなかった… という初めて知る事実に驚愕

Properties

age++ //=> Unary operator '++' cannot be applied to an operand of type '@lvalue Int'

昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/Properties.html を読む。

  • structインスタンスletならプロパティがvarでも値変更できない=>コンパイルエラー
  • クラスのインスタンスletでもプロパティがvarなら値を変更できる
  • 遅延プロパティは lazy 修飾子を宣言の前につける
    • lazy ならvarである。letlazyにできない
    • 遅延プロパティが有益なのは
      • 初期値が外部要因に依存しててインスタンスの初期化時に決まらない時
      • 初期値を決めるのに複雑計算量が多い時
    • 遅延プロパティにマルチスレッドで同時にアクセスしたとき一度しか初期化されないという保証はない
  • プロパティ値をインスタンス変数に保持しておく Objective-C みたいなやりかたはやらない
  • 計算型プロパティのsetterのパラメータ名指定は set(パラメータ名) デフォルトのパラメータ名は newValue
  • 読み取り専用の計算型プロパティであっても宣言は var
  • オブザーバーとは willSetdidSet
    • 新しい値がプロパティの現在の値と同じであっても、プロパティの値が設定されるたびに呼び出される
    • 定義できるのは lazy プロパティ以外
    • サブクラスでオーバーライドできる
    • willSet のデフォルトパラメータ名は newValue
    • didSet のデフォルトパラメータ名は oldValue
    • superクラスの初期化が終わった後、subクラスの初期化中、superクラスのプロパティのオブザーバーは呼び出される
    • クラス自身のプロパティ設定中、superクラスの初期化が呼ばれる前は、呼び出されない
    • inout宣言されたfuncの引数にプロパティを渡すとオブザーバーがいつも呼び出される
  • グローバル定数・変数がつかえる…のを今知った
    • いつも遅延評価される。lazy修飾子をつける必要は無い。つけたらコンパイルエラー
    • ローカル定数変数は決して遅延評価されない
    • 計算型にできる、オブザーバーを定義できる
  • 型プロパティは要するに static のこと
    • 初期化子が無いのでデフォルト値が必要
    • マルチスレッドで同時にアクセスしても一度だけしか初期化されないことが保証されている
    • staticではなくclassキーワードを使うとサブクラスでオーバーライドできる

Classes and Structures

光速に近づくと時間がゆっくり進むらしい。 つまり飛行機や新幹線の中で仕事をすると時間に余裕が生まれる。

昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html を読む。

  • 一般的なガイドラインとして、構造体や列挙型が好ましい。クラスは適切か必要なときに使うがよい
  • 実際にはカスタムデータ型のほとんどが構造体や列挙型
  • 型名(クラス名、構造体名、列挙型名)には、UppserCamelCase
  • プロパティ名とメソッド名には、lowerCamelCase
  • プロパティにアクセスする dot syntax は空白なし
  • memberwise initializer があるのは構造体だけ
  • 構造体と列挙型は値型
  • クラスは参照型
  • 同一演算子 === !== が使えるのはクラスのインスタンスだけ

なんだか「ふつうstructenumだよね」みたいなことをいわれたけど 気にしないでclassを使っていくスタイル。

Enumerations

enum 吉凶 {
    case 大吉, 吉, 中吉, 小吉, 末吉, 凶
}

前回に続いて https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html を読んでいる。

メモ

  • 列挙型の名前には複数形より単数形を与えよ
  • 型推論できるときは簡略形で書ける let x: Planet = .mercury
  • CaseIterable はSwift4.2から
  • 関連付けられた値をswitchcase構文の中で取り出す case .upc(let numberSystem, let manufacturer, let product, let check):
  • letをまとめて外に出せる case let .upc(numberSystem, manufacturer, product, check):
  • 暗黙の raw values にできるのは整数か文字列だけ
  • enum再帰 関連付けられた値に自分自身のEnum型を使う場合 indirect

enum は A Swift Tour でもう充分に驚いたので ここではそんなに驚きは少なかった。

Closures

lambda を「らんびだ」と呼んでいた人を思い出す。

前回に引き続いて https://docs.swift.org/swift-book/LanguageGuide/Closures.html を読んでいる。

気になった事

  • グローバル関数とネストされた関数はクロージャの特別なやつ
  • 一般的な形式 reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
  • 型推論できる型は省略できる reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
  • クロージャの本体が式一個のときは return を省略できる reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
  • 引数リストを簡略表記にして in も省略できる reversedNames = names.sorted(by: { $0 > $1 } )
  • 演算子メソッドを使う場合 reversedNames = names.sorted(by: >)
  • 関数の最後のパラメータにクロージャを渡す場合は括弧()の外側にぶら下げられる reversedNames = names.sorted() { $0 > $1 }
  • クロージャが唯一のパラメータなら括弧()も省略できる reversedNames = names.sorted { $0 > $1 }
  • 値のキャプチャーは他のプログラム言語のラムダ式なんかと同じ
  • 渡したクロージャが何処かに登録されて後で使われるような場合 @escaping を「パラメータ名:」と「型名」の間に書く func addEventListener(l: @escaping () -> Void) {〜} この場合 @escaping を付けないとコンパイルエラー
  • 関数に式を渡すとき自動的にクロージャにしてくれる @autoclosure を「パラメータ名:」と「型名」の間に書く func log(_ message: @autoclosure () -> String) {〜}
  • @autoclosure は遅延評価に便利
  • @autoclosure の使いすぎに注意。 訳わからんようなるので

いままで読んだ中でクロージャのところがいちばん面白かった。

Functions

土日のほうがやることが多いのはなぜか

前回に引き続いて https://docs.swift.org/swift-book/LanguageGuide/Functions.html を読んでいる。

気になった事

  • Void 型の関数は空のタプルを返す
  • 関数が返した値を使わない時 _ = f()
  • タプルのオプショナル型 (Int, Int)?
  • argument label と parameter name
  • argument label の省略 _
  • デフォルト値 func f(a: Int, b: Int = 123)
  • 可変パラメータ func f(_ numbers: Double...) -> Double { 中身は配列
  • 変数渡し func swap(_ a: inout Int, _ b: inout Int) { swap(&x, &y) デフォルト値や可変パラメータにはできない
  • 関数型の変数 var f: (Int, Int) -> Int = g
  • 関数型のパラメータ func g(_ f: (Int, Int) -> Int) {
  • 関数型の帰り値 func f() -> (Int) -> Int {
  • 関数のネスト