在 Swift 中,inout 關鍵字用於定義輸入輸出參數,允許函數修改傳入參數的原始值(而非副本),實現“傳引用”的效果(本質是“傳值+回寫”的語法糖)。以下是 inout 的核心用法、規則及示例:

一、基本用法

1. 函數參數聲明

在函數參數類型前添加 inout,表示該參數可被修改並反映到原始變量。

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

var x = 5, y = 10
swapTwoInts(&x, &y) // 調用時需加 & 符號
print(x, y) // 輸出:10 5
2. 調用規則
  • 傳入的參數必須是變量(不能是常量或字面量);
  • 調用時需在變量前加 &,顯式標記“允許修改”。

二、進階場景

1. 修改結構體/枚舉實例

inout 可用於修改結構體或枚舉的屬性(甚至整個實例):

struct Point {
    var x: Int, y: Int
}

func moveUp(_ point: inout Point, by distance: Int) {
    point.y += distance
}

var p = Point(x: 0, y: 0)
moveUp(&p, by: 5)
print(p) // 輸出:Point(x: 0, y: 5)
2. 結合類型別名/泛型
typealias IntPair = (a: Int, b: Int)

func modifyPair(_ pair: inout IntPair) {
    pair.a *= 2
    pair.b += 3
}

var pair = (a: 2, b: 4)
modifyPair(&pair)
print(pair) // 輸出:(4, 7)

// 泛型示例
func reset<T>(_ value: inout T, to defaultValue: T) {
    value = defaultValue
}

var str = "Hello"
reset(&str, to: "World")
print(str) // 輸出:World
3. 嵌套函數/閉包中的 inout

閉包若需捕獲 inout 參數,需顯式標記 inout(Swift 5.3+):

func outerFunc(_ num: inout Int) {
    let closure: (Int) -> Void = { increment in
        num += increment // 直接修改外部 inout 參數
    }
    closure(10)
}

var num = 5
outerFunc(&num)
print(num) // 輸出:15

三、注意事項

  1. 不可用於常量/字面量
    傳入的參數必須是 var 變量,不能是 let 常量或字面量(如 5"abc")。
  2. let 參數的區別
    普通參數默認是 let(不可修改),inout 參數本質是“可寫的變量”。
  3. 值類型 vs 引用類型
  • 對於值類型(結構體、枚舉、基本類型):inout 會修改原始值;
  • 對於引用類型(類):即使不用 inout,也能修改實例屬性(inout 僅用於修改引用本身,如替換整個實例)。
class Person { var name: String = "" }

// 修改屬性(無需 inout)
func changeName(_ p: Person) {
    p.name = "Alice"
}

// 替換實例(需要 inout)
func replacePerson(_ p: inout Person) {
    p = Person()
    p.name = "Bob"
}

var person = Person()
changeName(person)
print(person.name) // Alice

replacePerson(&person)
print(person.name) // Bob
  1. 不能與 let/var/@escaping 同時使用
    inout 參數不能標記為 let/var,也不能與 @escaping 同時修飾(避免逃逸閉包長期持有導致原始值失效)。

四、典型應用場景

  • 交換兩個變量的值(如 swap 函數);
  • 批量修改結構體/枚舉的屬性;
  • 函數需要“返回多個修改後的值”(替代元組返回);
  • 底層優化(減少值類型的拷貝開銷)。

通過 inout,Swift 在保持值類型安全性的同時,提供了靈活的參數修改能力,是處理“需要函數修改外部變量”場景的核心工具。