內容目錄
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
- 如果你的
class
或func
的功能已經完備 - 想避免Subclass繼承後改寫父類的
func
, properties,subscript
- 提升效能(可參考 四、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"]