読者です 読者をやめる 読者になる 読者になる

うさがにっき

読書感想文とプログラムのこと書いてきます

クラス、構造体、列挙型などについて

swift

概要

  • クラス、構造体、列挙型について
  • プロパティの扱い
  • 初期化の後回しについて
  • 型を扱う色々な機能
  • 関数型言語の機能
  • 関数型言語を使った関数を簡略化

詳細

クラス、構造体、列挙型について

各定義の仕方
クラスは参照型、構造体は値型

// クラス
class Store {
    init(location: Location, kind: Kind) {
        self.location = location
        self.kind = kind
    }
    
    var location: Location
    var kind: Kind
}

// 構造体
struct Location {
    var latitude: Float
    var longitude: Float
}

// 列挙型
enum Kind {
    case Convenience
    case Stationery
    case Drug
}

プロパティの扱い

プロパティの種類

swiftのプロパティには以下の二種類がある
単純に定数や変数を格納する「格納型プロパティ」
読み込み、書き込みのアクセスがあったときに計算や処理によって値を生成する「計算型プロパティ」

class Apple {
    // 格納型プロパティ
    let price = 100
    var totalPrice = 0
    
    // 計算型プロパティ
    // countが設定されれば、totalPriceが必ず計算される
    var count: Int {
        get {
            return totalPrice / price
        }
        set {
            // newValueはセットされる値
            totalPrice = price * newValue
        }
    }
    // 計算型プロパティで読み取り専用
    var description: String {
        return "totalPrice=\(totalPrice)"
    }
}

//実際の使い方
var a = Apple()
// newValueに8が入る
a.count = 8
// 8になる
println(a.count)
// "totalPrice=800となる"
println(a.description)
プロパティの変更を検出

swiftでは「willSet」、「didSet」で格納型プロパティの値が変更されたときに自動で検出してくれる機能がある

class Counter {
    var count: Int = 0 {
        willSet {
            println("現在の値:\(count)")
            println("新しい値:\(newValue)")
        }
        
        didSet {
            println("変更前の値:\(oldValue)")
        }
    }
}

変数の初期化について

swiftでは画像の初期化など処理の重い処理を実際に使うまで後回しすることができる
初期化自体を後回しすることにより重い変数を持ったままずっと処理していく必要がない

class Store {
    lazy var image = UIImage(named: "sample.jpg")
}

// この時点では画像は初期化されていない
var s = Store()
// 画像を使う段階になってはじめて初期化(ロード処理)が走る
var image = s.image

型を扱う様々な機能

extention

既存の型にメソッドやイニシャライザなどを追加できる

extension Double {
    var mm:Double {
        return self / 1000.0
    }
}

// 結果は0.0254
let oneInch = 25.4.mm
Any型、AnyObject型
  • Any型は「あらゆる型」
  • AnyObject型は「あらゆるクラスの型」

宣言時に使えたり、as演算子を使い、特定の型にダウンキャストできたりする

var model: AnyObject = "iPhone6"

// as演算子を使うと特定の型にキャスト出来る
var modelName: String = model as String

// as?を使うとキャストに成功した場合はOptionalにラップした型に変換して代入
// キャストに失敗したらnilを代入
var versionName: String? = model as? String

is演算子を使って型の判定ができる

let data = ["iPhone6", 8, "Apple"]
var textCount = 0
for item in data {
    if item is String {
        textCount++
    }
}

// 2
println("\(textCount)")
タプル

複数の値を一つの値として扱える

var device = ("iPhone6", 8, "Apple")

var name = device.0
var version = 1
var vender = device.2
ジェネリクス

Javaと一緒
汎用的な型で関数を定義できる

func toArray<T>(values: T...) -> [T] {
    var result = [T]();
    for value in values {
        result.append(value)
    }
    
    return result
}

// 色々な型の値を扱える
let indices = toArray(1, 2, 3, 4)
let names = toArray("iPhone6", "iPhone 5s")
let numbers = toArray("1", 2, 3.0, false)

関数型言語の機能

変数に関数を使う

関数を変数のように扱える
代入だけではなく、引数や戻り値にすることも可能

func sayHello(name: String) -> String {
    return "Hello, \(name)!"
}

// 関数の型を型として指定し、関数を変数に代入
var hello: String -> String = sayHello

println(hello("hiro"))
クロージャ

引数として関数を入れるところに直接式を入れてしまう
sorted関数(第二引数の条件に従って並び替えをする)を使って、クロージャを使わずに文字列の並び替えを行うと下記になる

let names = ["Orance", "Apple", "Banana"]

func asc(a: String, b: String) -> Bool {
    return a < b
}

sorted(names, asc)

これをクロージャを使うとこうなり、コードがシンプルになる

let names = ["Orance", "Apple", "Banana"]

// クロージャは{引数 -> 戻り値 in}
sorted(names,{ (a:String, b:String) -> Bool in
        return a < b
})

クロージャは文脈から推測できる指定は省略可能という機能がある
なので次のようにもかける

let names = ["Orance", "Apple", "Banana"]

sorted(names,{ a, b in return a < b })

関数型言語を使った言語の簡略化

関数はパラメータが多くなると使いにくくなる
それを防ぐ方法が部分適用とカリー化関数

部分適用

返り値を関数とすることにより、引数の使い回しを行う方法

// 第一引数が同じものを繰り返したいとする
func say(message: String) -> (String -> String) {
    func sayName(name: String) -> String {
        return message + ", " + name + "!"
    }
    
    // 返りを関数に
    return sayName
}

var hello = say("Hello")
hello("paul")
hello("gene")
カリー化関数

複数の引数を取る関数を、1つの引数を取る関数の連鎖に変換すること

func say(message: String)(name: String) -> String {
    return message + ", " + name + "!"
}

var hello = say("Hello")
hello(name: "Paul")
hello(name: "Gene")

say("Hello")(name: "Tommy")