一年寫一次,一次寫一批,一批寫完後休息一年,在 WWDC 20 前又回來了,由於又有新素材了嘛。Swift 在 5.1 以後逐漸進入成熟期,因此 Swift 5.2 中的語言新特性多數是小修小補,既然這些特性在最新的 Xcode 正式版已經能夠用了,咱們不妨一塊兒瞭解一下吧。本期主題:callAsFunction
bash
遙想當年在大一的 C++ 課堂上老師介紹的 function call operator,哇,真是神奇,一個對象能夠當成函數那樣調用呢!它還有一個好聽?的名字叫作函數對象,也有的叫作函數子(functor)。先來一段 C++ 回味一下。函數
struct Adder
{
public:
Adder(int base):m_base(base){}
int operator()(int a) {
return m_base + a;
}
private:
int m_base;
};
int main(int argc, const char * argv[]) {
int adder = Adder(2);
cout << adder(6) << endl; //8
return 0;
}
複製代碼
函數就是函數,爲何須要搞得那麼複雜呢?緣由是與普通的函數不一樣, Adder
是帶狀態的。後來的 C++ 11 中引入了 lambda 特性(相似於 Swift 的 closure),它的一種常見實現方式,就是編譯成上面的函數對象。ui
如同 C++ 98 中的 函數對象,Swift 5.2 中的 callAsFunction
是個徹頭徹尾的上世紀特性。Kotlin 中也有相似的 invoke
operator,因此對 Swift 來講不是啥發明,只是下定決心把這個小小語法糖給加上了。咱們來看一下 Swift 的版本:spa
struct Adder {
var base: Int
func callAsFunction(_ x: Int) -> Int {
return base + x
}
}
let add2 = Adder(base: 2)
print(add2(6)) // 8
複製代碼
這裏的 callAsFunction(...)
函數,就是Swift 編譯器約定的名字,這個函數能夠有 0-N 個參數,甚至不定參也能夠的。除了函數名字的約定,基本上沒有任何能夠限制你發揮的地方,你能夠加上泛型,甚至能夠用 class
或者 enum
,固然這種對象通常是值類型語義,因此類型定義成struct
是最多見的,其次是enum
也能夠的,而定義成class
的話一要記得引用類型的開銷,二是必須給它添加init
構造函數。code
好學的寶寶可能要問爲何上面 C++ 的例子可不能夠是class
呢?其實,在 C++ 的例子中使用 class
或者 struct
是同樣的,C++ 中 class
和 struct
的最主要的區別在於成員的默認訪問級別是什麼,而在上面的例子中咱們指定了訪問級別。在 C++ 中,對象構造在堆上仍是棧上是使用者控制的,這點與 Swift 是不一樣的。對象
下面的這個例子顯示,callAsFunction
僅僅是一個語法糖,能夠直接用這個名字進行調用。編譯器
let add2 = Adder(base: 2)
print(add2(6)) // 8
print(add2.callAsFunction(6)) // 8
複製代碼
在 Swift 中這種不是函數,但能夠當成函數同樣調用對象還有哪些呢?咱們來盤點一下:string
callAsFunction
也能夠被賦值給函數類型,供以後調用,這不是針對callAsFunction
的新特性,對於其餘名稱的方法也能夠這樣。let f: (Int) -> Int = add2.callAsFunction(_:)
print(f(6)) // 8
複製代碼
類型名稱,咱們常常使用 UIView(...)
形式來構造對象,但實際上這個語法糖會被轉換成函數調用 UIView.init(...)
it
@dynamicCallable
修飾的類型,多用於與動態語言的交互。io
@dynamicCallable struct DummyCallable {
func dynamicallyCall(withArguments: [Int]) {
print(withArguments)
}
func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {
print(withKeywordArguments)
}
}
let x = DummyCallable()
x(1,2,3) // [1, 2, 3]
x(Leon: 28, 178) // ["Leon": 28, "": 178]
複製代碼
從某種程度上來說,callAsFunction
能夠看做是這種形式的靜態小夥伴。