開発メモ

開発関係のメモをいろいろと。たぶん。

The Swift Programming Languageのメモ(その6)

はじめに

これは、『The Swift Programming Language』を読んだ時の個人的なメモです。なので、引用はすべて『The Swift Programming Language』から。

iTunes - ブック - Apple Inc.「The Swift Programming Language」
https://itunes.apple.com/jp/book/swift-programming-language/id881256329?mt=11

その5はこちら。

The Swift Programming Languageのメモ(その5) - 開発メモ
http://seeku.hateblo.jp/entry/2014/06/09/195456


Closures

  • グローバル関数やネストした関数はクロージャの特殊な形だよ
  • クロージャには以下の3つの形があるよ
    • グローバル関数(名前あり。何もキャプチャしない)
    • ネストした関数(名前あり。関数の中をキャプチャ)
    • クロージャ(名前なし。周りの環境をキャプチャ)

The Sort Function

  • ソートに関数を使うとこんな感じになるよ
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = sort(names, backwards)
// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
  • やりたいことは単純な比較なのに、大げさすぎるよね?

Closure Expression Syntax

{ (parameters) -> return type in
    statements
}
  • 引数は定数でも変数でもinoutでも良いよ
  • デフォルト値は使えないよ
  • 可変引数は最後にかけば使えるよ
  • タプルは引数にも戻り値にも使えるよ

  • ソートにクロージャを使うとこんな感じになるよ

reversed = sort(names, { (s1: String, s2: String) -> Bool in
    return s1 > s2
    })
  • 引数や戻り値が『{}』の中に来るから要注意だよ
  • 本文が短いと、1行にまとめて書くことも出来るよ
reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )

Inferring Type From Context

  • Swiftは引数や戻り値の型を自動的に推測するよ
    推測できる型は、書かなくても大丈夫だよ。
    戻り値の型を推測できる場合、戻り値の『->』も省略できるよ。
reversed = sort(names, { s1, s2 in return s1 > s2 } )

Implicit Returns from Single-Expression Closures

  • 式が1つだけのクロージャは、その値を返すと見なす事が出来るよ
    つまり、『return』も省略できるよ。
reversed = sort(names, { s1, s2 in s1 > s2 } )

Shorthand Argument Names

  • Swiftのクロージャには、引数の代わりに使える特殊変数が用意されてるよ
    $0、$1、$2って感じの名前で使えるよ。

  • これを使う場合、引数も『in』も省略できるよ

reversed = sort(names, { $0 > $1 } )

Operator Functions

  • 実は、もっと短く書く方法があるよ
  • Swiftでは、『>』を2つのStringを引数としてBoolを返す関数として実装してるよ
  • だから、関数を必要とするsort()にそのまま使うことが出来るよ
reversed = sort(names, >)

メモ: ここまで行ったら逆にわかりにくくない?

Trailing Closures

  • 関数の最後の引数がクロージャの場合、後端記法(?)が便利だよ
    メモ: ちゃんとした用語はあるのか?

  • 後端記法だと引数の『()』の外に、クロージャを書くよ

  • 通常の記法だとこんな感じ
someFunctionThatTakesAClosure({
    // closure's body goes here
    })
  • 後端記法だとこんな感じ
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

メモ: ネストした関数との区別はどうなってるのか?

  • クロージャだけが引数の場合、実は『()』も省略できるよ
  • ソート関数に後端記法を使うとこんな感じになるよ
reversed = sort(names) { $0 > $1 }

Closures Are Reference Types

Enumerations

  • Swiftの列挙型はCのに比べてずっと柔軟だよ

Enumeration Syntax

  • 列挙型の定義はこんな感じになるよ
enum CompassPoint {
    case North
    case South
    case East
    case West
}
  • 型が推測できる場合、型の指定なしで列挙型のメンバーが使えるよ
    directionToHeadがCompassPointの場合、こんな感じで書けるよ
directionToHead = .East

Associated Values

  • Swiftの列挙型では、メンバーごとに自由な型で値を持たせることが出来るよ
  • 具体的にはこんな感じになるよ
enum Barcode {
    case UPCA(Int, Int, Int)
    case QRCode(String)
}
  • 実際にメンバーを使う時は、こんな感じになるよ
var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
  • switchで値を取り出す時は、こんな感じになるよ
switch productBarcode {
case .UPCA(let numberSystem, let identifier, let check):
    println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
case .QRCode(let productCode):
    println("QR code with value of \(productCode).")
}
// prints "QR code with value of ABCDEFGHIJKLMNOP.
  • いちいち、letやvarを書くのが面倒な時は、最初にまとめることが出来るよ
switch productBarcode {
case let .UPCA(numberSystem, identifier, check):
    println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
case let .QRCode(productCode):
    println("QR code with value of \(productCode).")
}
// prints "QR code with value of ABCDEFGHIJKLMNOP.

Raw Values

  • すべてのメンバーに共通の型で値を持たせることも出来るよ
    この場合、事前に元の値(raw value)を持たせることになるよ。

  • 具体的にはこんな感じになるよ

enum ASCIIControlCharacter: Character {
    case Tab = "\t"
    case LineFeed = "\n"
    case CarriageReturn = "\r"
}
  • 元の値には文字列型、文字型、整数型、浮動小数点型が使えるよ
  • 複数のメンバーで、同じ値は使えないよ
  • 元の値に整数型を使う場合、特に指定しないと自動インクリメントされるよ

  • 元の値は『toRaw()』で取り出すことが出来るよ

let earthsOrder = Planet.Earth.toRaw()
// earthsOrder is 3
  • 『fromRaw()』で元の値から列挙型を生成できるよ
let possiblePlanet = Planet.fromRaw(7)
// possiblePlanet is of type Planet? and equals Planet.Uranus
  • fromRaw()はオプション変数を返すよ

Classes and Structures

  • クラスと構造体はプロパティとかメソッドから作られる、よくあるやつだよ
  • Swiftでは、定義と実装を同じファイルに書くよ

Comparing Classes and Structures

  • クラスも構造体も次のようなことが出来るよ

    • 値を格納するプロパティを定義出来るよ
    • メソッドを定義出来るよ
    • 『[]』でアクセスするsubscriptsを定義出来るよ
    • イニシャライザーを定義できるよ
    • 機能を拡張できるよ
    • プロトコルを適用できるよ
  • これらに加えて、クラスにはこんな機能もあるよ

    • クラスの継承が出来るよ
    • 実行時に型をチェックしたりキャストしたり出来るよ
    • インスタンスが破棄されるときにdeinitが呼び出されるよ
    • ARCでインスタンスを管理してくれるよ

メモ: Type castingが出来るのはクラスだけ? 要確認

Accessing Properties

  • 深い階層のプロパティに直接代入できるよ!
someVideoMode.resolution.width = 1280
println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// prints "The width of someVideoMode is now 1280"

Memberwise Initializers for Structure Types

  • すべての構造体は、プロパティ指定付きのイニシャライザーを持つよ
    これは、自動で生成されるよ。
let vga = Resolution(width: 640, height: 480)

Structures and Enumerations Are Value Types

  • 構造体と列挙型は値型だよ
    ここだけの話、Swiftの基本型はすべて値型で構造体だったりするよ。
    メモ: 要確認

Classes Are Reference Types

  • クラスは参照型だよ
    参照型はコピーされないよ。

  • 参照型を定数(let)に入れても、その中のプロパティは変更できるよ

let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0

Identity Operators

  • 複数の変数が同じインスタンスを参照しているかどうか調べる方法があるよ
  • 『===』で同じ参照かどうか、調べることが出来るよ
  • 『!==』で同じじゃない事を調べることが出来るよ

Assignment and Copy Behavior for Collection Types

  • Swiftでは、配列も辞書も構造体として実装されてるよ

  • NOTE: プログラムでコピーを行うと、常にコピーが作られるようにみえるよ。けど、Swiftの場合、絶対に必要になった時だけ、実際のコピーが行われるよ。Swiftは値のコピーを出来るだけ最適化するから、コピーを避けるような事はしなくていいよ。
    メモ: 要確認

Assignment and Copy Behavior for Dictionaries

  • 辞書がコピーされる場合、こんな感じになるよ

    • キーや値として値型が格納されてる場合、値がそのままコピーされるよ
    • 参照型が格納されてる場合、参照がコピーされるよ
  • コピーに関する動作は、構造体のプロパティでも同じようになるよ

Assignment and Copy Behavior for Arrays

  • 配列のコピーも辞書と同じだよ

とりあえずここまで。
(2014/06/10 作成)
(2014/09/25 修正)