今天,在看 Then 源碼時,發現了一處比較值得研究的地方
public func with(_ block: (inout Self) -> Void) -> Self {
var copy = self
block(©)
return copy
}
這部分代碼是在針對 Any
類型的協議擴展里實現的。這里 with
的語義是拷貝值類型并修改(代碼中針對的是 Any
,這里用值類型來說明問題)。可以看看官方的示例:
let newFrame = oldFrame.with {
$0.size.width = 200
$0.size.height = 100
}
newFrame.width // 200
newFrame.height // 100
注意,這里使用的是 inout
關鍵字,而且已經把它的位置放在了類型之前,這是 Swift3 的新變化 Adjusting inout Declarations for Type Decoration。
在函數調用時,如果傳遞的參數是引用類型,那么我們在函數中對參數的修改會直接影響到傳進來的變量,這就是函數的副作用。
然而,如果傳遞的參數是值類型的話,我們在函數中對參數是不可以進行修改的,因為傳參時函數會創建一個不變量來存儲值,我們不可以對這個不變量進行修改。在 Swift2 中有個關鍵字 var
可以讓函數創建一個變量來存儲值,這樣我們就可以在函數中對這個變量進行修改了。不過在 Swift3 中已經去掉了這個關鍵字 Removing var from Function Parameters。
如果想讓值類型具備引用類型的語義,這時 inout
關鍵字就出場了。這個有點類似 C 語言中傳遞指針,我們在調用時需要加上 &
標識。這樣,我們就可以愉快的對值類型進行修改了。不過,為了避免函數副作用,我們最后不要這樣做。