今日の学習

C言語的な部分が多分に残っている。
ちぐはぐ。Rubyとかのスッキリした文法では決してない。
いまのところ使いこなせる自信ない。

//
//  main.swift
//  Swift2First
//
//
// https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
import Foundation

do {
    let name = "Ste"
    var age = 56
    var age2 : Int = 32
    print("\(age) \(name)")
    var phone :Optional<String> = nil
    var phone2:String? = nil

    // Optional - Optional binding
    phone = "aaa"
    if phone != nil {
        print(phone)
    }
    if let p = phone {
        print(p)
    }
    // Optional Chaining nilはBoolのfalseじゃないの。
    // ?? 演算子
    if phone?.hasPrefix("a") ?? false {
        print(phone)
    }
}

do {
    // Tuple
    let ste = ("Ste",56)
    let (name,age) = ste
    print(ste.0)

    let steeve = (name:"Steeve",age:56)
    print(steeve.name)
}

do {
    // Array
    let fishes = ["aaa","bbbb"]
    print(fishes[0]);//xcode 補完ちょっとバカ
    for fish in fishes {
        print(fish)
    }
    var dogs:[String] = []
    dogs.append("aaa");

}

do {
    // Set
    let fishes : Set<String> = ["aaa","bbbb"]
    if fishes.contains("aaa") {
        print("contain")
    }
}

do {
    // Dictionary
    // sizeOfFishes["Mackerel"] のようにキーを用いてアクセスできる。このとき返ってくるのは Int? 型であり、キーが存在しない場合の値は nil である。
    var size_ : [ String : String ] = [:]
    size_["hoge"] = "fuga"
    size_["hogehoge"] = "fuga"
    if let n = size_["hoge"] {
        print(n)
    }
    // Optional - binding
    if let n = size_["hoge2"] {
        print(n)
    }else{
        print("not contain")
    }
    for key in size_.keys {
        print(size_[key])
        // => Optional - binding必要
    }
    // tupleで取り出すのがよいのか。
    for (key,value) in size_ {
        print("\(key) - \(value)")
    }
}

do {
    // Where
    for i in 0..<3 where i % 2 == 0 {
        print(i)
    }
}

do {
    let numbers: [Int?] = [0, nil, 3, 4, nil]
    // ?でnilの時は何もおきない
    for case let i? in numbers {
        print(i)
    }
}

do {
    let number = 1
    // これちょっと気持ち悪いな。
    if case 0..<3 = number {
        print(number)
    }

    // なぜ ifだけでややこしい
    let condition = true
    let aNumber: Int? = 3
    let anotherNumber: Int? = 7
    // Optional bindingしているの?
    if condition, let a = aNumber, let b = anotherNumber where a < b {
        print(a + b)
    }
    if let a = aNumber, let b = anotherNumber where a < b {
        print(a + b)
    }
    if true,let a = aNumber, let b = anotherNumber where a < b {
        print(a + b)
    }
}

do {
    // Functions 
    // 呼び出し時には引数にラベルをつける。ただし第一引数にはラベルをつけない
    func multiply(number first: Int, by second: Int) -> Int {
        return first * second
    }
    print(multiply(number: 3, by: 5))
}

do {
    // var
    func increment(var number: Int) -> Int {
        return ++number
    }
    increment(6)
}

do {
    // inout -> Intいらない -> Voidで明示的に
    func increment(inout number: Int) -> Void {
        ++number
    }
    var number = 7
    // 参照渡し Cっぽい
    increment(&number) // => 8
}

do {
    // Default value
    func refrain(string: String, count: UInt=1) -> String {
        var result: [String] = []
        for i in 0..<count {
            result.append(i == 0 ? string : string.lowercaseString)
        }
        return result.joinWithSeparator(", ")
    }

    refrain("Let it be", count: 3)
    
    refrain("Love")
}

do {
    // 可変長引数
    // 型名に続いて ... と書くと可変長の引数を受けられるようになる。実装中においては Array として取り扱うことができる。
    func sum(numbers: Int...) -> Int {
        return numbers.reduce(0, combine: +)
    }
    sum(1, 4, 7)
}

do {
    // 関数はファーストクラス
    func multiply(number first: Int, by second: Int) -> Int {
        return first * second
    }

    var calculation: (Int, Int) -> Int

    calculation = multiply
    // ()でcall
    let twentyOne = calculation(3, 7)
}

do {
    // 高階関数
    func multiply(number: Int, by: Int) -> Int { return number * by }
    func add(number: Int, to: Int) -> Int { return number + to }

    func calculation(kind: String) -> (Int, Int) -> Int {
        switch kind {
        case "add":
            return add
        case "multiply":
            return multiply
        default:
            fatalError("Unsupported")
        }
    }
    
    calculation("add")(1, 4)
}

do {
    // 関数のネスト
    func calculation(kind: String) -> (Int, Int) -> Int {
        func multiply(number: Int, by: Int) -> Int { return number * by }
        func add(number: Int, to: Int) -> Int { return number + to }

        switch kind {
        case "add":
            return add
        case "multiply":
            return multiply
        default:
            fatalError("Unsupported")
        }
    }
    
    calculation("add")(1, 4)
}

do {
    // guard
    let contact = [ "name" : "Steve Jobs", "mail" : "steve@apple.com" ]

    func recipient(contact: [String: String]) -> String? {
        guard let name = contact["name"], let mail = contact["mail"] else {
            return nil
        }
        // スコープname,mailはここまでスコープ来る
        return "\(name) <\(mail)>"
    }
}

do {
    // CLosures
    func doubling(number: Int) -> Int {
        return 2 * number
    }

    let values = [0, 1, 2, 3, 4, 5]
    // mapは非破壊的 変数で受け取らないとだめっぽ
    var v = values.map(doubling)
    // =>が クロージャで
    var v2 = values.map({ (number: Int) -> Int in
        return 2 * number
    })
    // 省略クロージャ達
    var v3 = values.map({ number in 2 * number })
    var v4 = values.map({ 2 * $0 })
    var v5 = values.map { 2 * $0 }
}

do {
    // キャプチャ
    // ちょっと理解に苦しみますね。使わないようにしよ
    // 面白いけど。
    func counter() -> () -> Int {
        var count = 0
        let closure = {
            return ++count
        }
        return closure
    }

    let c = counter()
    c()
    c()
}

do {
    // enum
    enum ArithmeticOperation {
        case Add
        case Substract
        case Multiply
        case Divide
    }
    // enum with associate value
    enum Diagram {
        case Line(Double)
        case Rectangle(Double, Double)
        case Circle(Double)
    }

    func calculateArea(diagram: Diagram) -> Double {
        let area: Double
        switch diagram {
        case .Line(_):
            area = 0.0
        case let .Rectangle(width, height):
            area = width * height
        case .Circle(let radius):
            area = radius * radius * M_PI
        }
        return area
    }
    
    calculateArea(.Circle(3.0))
}

do {
    // struct
    struct Body {
        let height: Double
        let mass: Double
    }

    let myBody = Body(height: 129.3, mass: 129.3)

    func calculateBodyMassIndex(body: Body) -> Double {
        let meterHeight = body.height / 100.0
        return body.mass / (meterHeight * meterHeight)
    }
    
    calculateBodyMassIndex(myBody)
}
// だいぶC言語残っているな。。。

do {
    // class
    class Lot {
        var remains: [String]

        init(_ elements: String...) {
            self.remains = elements
        }

        func choose() -> String? {
            if remains.isEmpty {
                return nil
            }
            let randomIndex = Int(arc4random_uniform(UInt32(remains.count)))
            return remains.removeAtIndex(randomIndex)
        }
    }

    func pickFromLot(lot: Lot, count: Int) -> [String] {
        var result: [String] = []
        // 警告ない例にしてほしいところ
        for _ in (0..<count) {
           lot.choose().map { result.append($0) }
        }
        return result
    }
    // new とかいらない
    let lot = Lot("Swift", "Objective-C", "Java", "Scala", "Perl", "Ruby")
    pickFromLot(lot, count: 3)
    print(lot.remains)
}

do {
    //ここで、二つのインスタンスが互いを参照し合うなどといった際に、永遠に参照カウントが0にならないということが起き得る。これを循環参照という。循環参照が起きるとメモリリークするので、一方を弱い参照(参照カウントに影響しない参照)にしてやる必要が出てくる。
    class Dog {
    }

    weak var dog: Dog?
    dog = Dog()
}

do {
    // クロージャのweak
    class Dog{}
    let dog = Dog()
    // キャプチャしている
    let callDog = { [weak dog] (message: String) -> String in
        return "\(dog!), \(message)."
    }
    
    callDog("stay")
}

do {
    // Computed Properties
    // Computed プロパティでは他の情報から計算可能な値をプロパティとして提供できる。
    struct Circle {
        var radius: Double = 0.0

        var area: Double {
            get {
                return radius * radius * M_PI
            }
            set (newArea) {
                radius = newArea
            }
        }
    }
    var circle = Circle()
    print(circle.radius)
    circle.area = 1.0
    print(circle.area)
}

do {
    // Property Observers
    // willSet や didSet ブロックを書くことで、プロパティの値の変化の前後に何らかの処理を行うことができる。
    // つかわね。
    struct Dam {
        let limit = 100.0
        var waterLevel = 0.0 {
            willSet {
                print("\(newValue - waterLevel) will change")
            }
            didSet {
                if waterLevel > limit {
                    print("Bursted")
                    waterLevel = limit
                }
                print("\(waterLevel - oldValue) did change")
            }
        }
    }
    
    var dam = Dam()
    dam.waterLevel = 120
}

do {
    class Printer {
        var numberOfCopies = 1
        // self
        func put(string: String) {
            for _ in (0..<self.numberOfCopies) {
                print(string)
            }
        }
    }

    let printer = Printer()
    printer.put("Word")
}

do {
    struct StepCounter {
        var count: Int = 0
        // mutating
        mutating func step() -> Void {
            count++
        }
    }

    var counter = StepCounter()
    counter.step()
    print(counter.count)
}