[筆記] Swift深入淺出常見語法 – 關鍵字 Keywords

bookmark lot
分享

內容目錄

mutating

struct Animal {
  private var isHungry: Bool = false

  // error
  // func exercising() {
  //  isHungry = true //error: Cannot assign to 'isHungry' in 'self'
  // }

  // success: add 'mutating' keyword
  mutating func exercising() {
    isHungry = true
  }
}

@autoclosure

func goodMorning(morning: Bool, whom: String) {
    if morning {
        print("Good morning, \(whom)")
    }
}

func giveAname() -> String {
    print("giveAname() is called")
    return "Robert"
}

goodMorning(morning: true, whom: giveAname())

// How to make this inline?
// wrap it into a new function and add '@autoclosure' keyword
func goodMorningInline(morning: Bool, whom: @autoclosure () -> String) {
    if morning {
        print("Good morning, \(whom())")
    }
}
// use it
goodMorningInline(morning: true, whom: giveAname())
// outputs:
// giveAname() is called
// Good morning, Robert

// compare with the origin version
goodMorning(morning: true, whom: giveAname())
// outputs:
// giveAname() is called
// Good morning, Robert

看完是不是覺得好像只是在炫技而已呢?接下來說明他比較實際好用的地方,把 morning: 皆改為 false:

goodMorning(morning: false, whom: giveAname())
// outputs:
// giveAname() is called
// Good morning, Robert

goodMorningInline(morning: false, whom: giveAname())
// outputs: <no result>

原始版本,對編譯器來說就像這樣:

let name = giveAname()
goodMorning(morning: false, whom: name)

所以 giveAname() 無論如何都會先被執行。而使用@autoclosure除了簡化程式碼,也讓 whom 以 callback / closure 的方式作為參數執行。

inout

struct Bag {
  var status: Int
  init(status: Int) { self.status = status }
}

// (1) error
func refreshBagFromApi(_ bag: Bag) {
    // simulate a networking service api
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
        let newBag = Bag(status: 1)
        // Cannot assign to value: 'bag' is a 'let' constant
        bag = newBag
    }
}

// (2) success: add 'inout' keyword
func refreshInoutBagFromApi(_ bag: inout Bag) {
    // simulate a networking service api
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
        let newBag = Bag(status: 1)
        bag = newBag
    }
}

final

什麼時候該使用 final

  1. 如果你的 classfunc 的功能已經完備
  2. 想避免Subclass繼承後改寫父類的 func, properties, subscript
  3. 提升效能(可參考 四、Static vs Dynamic Dispatch

subscript

extension CardBook {
    subscript(index: Int) -> Card? {
        return self.cards.count > index ? self.cards[index] : nil
    }
    subscript(indexString: String) -> Card? {
        guard let index = self.cards.firstIndex { $0.number == indexString } else 
          return nil
        }
        return self.cards[index]
    }
}

var cardBook = CardBook()
let firstCard = cardBook[0]
let numberCard = cardBook["A123"]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *