把參數變成 closure 的 @autoclosure

@autoclosure 擁有把我們呼叫 function 時傳入的參數變成 closure 的神奇魔力,例如以下例子:

func play(_ sing: @autoclosure () -> String, at hour: Int) {   if hour >= 22 {      let song = sing()      print("深夜適合播放\(song)")   } else {      print("認真寫 iOS App")   }}

呼叫 play function 時,自動完成告訴我們第一個參數應該傳入字串,但剛剛我們明明將第一個參數的型別宣告為 () -> String 呀 ? 不是應該傳入 closure 嗎 ?

因為 () -> String前加了 @autoclosure的關係,Swift 會將我們傳入的參數變成 closure。我們只要傳入字串,它就能自動變成型別 () -> String 的 closure。

如以下例子,songs.randomElement()! 會成為被 { } 包起來的 closure { songs.randomElement()! }。又由於 { } 裡 songs.randomElement()! 是唯一的程式,所以 randomElement() 得到的字串會回傳,符合當初參數要求的型別 () -> String

let songs = ["真心不騙", "已讀不回"]play(songs.randomElement()!, at: 23)

結果

但是為什麼要使用 @autoclosure 呢 ? 以剛剛的例子來說,它可以帶來以下幾個好處:

1 傳入的參數不一定會執行。

songs.randomElement()! 不一定會執行。因為白天要認真寫 App,要等到晚上 22 點之後才能開始流淚播放悲傷的情歌。

if hour >= 22 {   let song = sing()   print("深夜適合播放\(song)")} else {   print("認真寫 iOS App")}

2 傳入的參數延後執行。

play(songs.randomElement()!, at: 23) 只是先傳入程式碼 songs.randomElement()!,要等 sing() 時才會執行。

其實我們平常開發 iOS App 時,很常使用的 assert function 就含有兩個參數是 @autoclosure 呢 !

func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line)

因為 @autoclosure 的關係,它的自動完成提示將如下圖, condition & message 的型別分別為 Bool 和 String,但最後其實會變成 () -> Bool 和 () -> String 型別的 closure 。

var songIndex = 5let songs = ["小幸運", "中幸運", "大幸運"]assert(songIndex < songs.count, "沒有這首歌!")

為什麼 assert 要將參數 condition & message 宣告為 @autoclosure 呢? 加了 @autoclosure,參數 condition & message 會變成 closure,不會馬上執行,於是 assert 可以檢查 build 的模式,只在 debug builds 時執行參數 condition & message 的 closure。

關於 @autoclosure,最後還有個 2 個小地方可以補充。

1 可以跟 @escaping 結合。

func play(_ sing: @escaping @autoclosure () -> String, at hour: Int) {}

2 它搭配的 function 型別必須沒有參數,因此 () -> String 可以,但 (Int) -> String 不行。

func play(_ sing: @autoclosure () -> String, at hour: Int) {}
Argument type of @autoclosure parameter must be '()'

彼得潘的 Swift iOS App 開發問題解答集

彼得潘和學生們在開發 iOS App 路上曾經解決的問題集

彼得潘的 iOS App Neverland

Written by

彼得潘的 Swift 程式設計入門,App程式設計入門作者,彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,http://apppeterpan.strikingly.com

彼得潘的 Swift iOS App 開發問題解答集

彼得潘和學生們在開發 iOS App 路上曾經解決的問題集

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade