Swift In-Out 參數 (In-Out Parameters)

在 Swift 中,函式的參數預設是常數 (Constant),也就是說你不能在函式內部修改參數的值。如果你試圖修改,編譯器會報錯。

但有時候,我們會希望函式能修改傳入的變數,並且讓這個修改保留到函式外部。這時候就需要使用 In-Out 參數

基本語法

1. 定義函式:使用 inout

在參數型別的前面加上 inout 關鍵字。

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

在這個例子中,swapTwoInts 函式接受兩個 inout 的整數。它會交換這兩個整數的值。

2. 呼叫函式:使用 &

當你呼叫一個接受 inout 參數的函式時,必須在傳入的變數名稱前面加上 & 符號 (Ampersand)。這表示原本的變數將會被修改。

var someInt = 3
var anotherInt = 107

swapTwoInts(&someInt, &anotherInt)

print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// 輸出 "someInt is now 107, and anotherInt is now 3"

運作原理:Copy-In Copy-Out

In-Out 參數的行為通常被描述為 Copy-In Copy-Out (或是 call by value result):

  1. Copy-In:當函式被呼叫時,參數的值被複製到函式內部。
  2. Modify:在函式執行期間,修改的是這個複本
  3. Copy-Out:當函式執行結束時,這個複本的值被賦值回原本的變數。

雖然在編譯器最佳化後,為了效能可能會變成直接參考記憶體位址 (Call by Reference),但理解這個行為模型能幫助你避免一些副作用問題。

重要限制與規則

  1. 必須傳入變數 (var):你不能傳入常數 (let) 或字面值 (Literal, 如 1"hello"),因為它們不能被修改。

    let constantNumber = 10
    // swapTwoInts(&constantNumber, &anotherInt) // 錯誤!不能傳入 let
    // swapTwoInts(&10, &anotherInt) // 錯誤!不能傳入字面值
    
  2. 不支援預設值:In-Out 參數不能有預設值。

  3. 不支援可變參數:可變參數 (Variadic Parameters, ...) 不能標記為 inout

常見應用場景

除了交換數值 (swap) 之外,常見的應用還包括:

  • 修改複雜的 Struct 屬性。
  • 在遞迴演算法中傳遞累加狀態。
  • 某些高效能的數學運算。

Swift 標準庫中的 swap(_:_:) 函式就是使用 inout 實作的。

var myName = "Mike"
var yourName = "John"
swap(&myName, &yourName)