在 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
三、注意事項
- 不可用於常量/字面量
傳入的參數必須是var變量,不能是let常量或字面量(如5、"abc")。 - 與
let參數的區別
普通參數默認是let(不可修改),inout參數本質是“可寫的變量”。 - 值類型 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
- 不能與
let/var/@escaping同時使用
inout參數不能標記為let/var,也不能與@escaping同時修飾(避免逃逸閉包長期持有導致原始值失效)。
四、典型應用場景
- 交換兩個變量的值(如
swap函數); - 批量修改結構體/枚舉的屬性;
- 函數需要“返回多個修改後的值”(替代元組返回);
- 底層優化(減少值類型的拷貝開銷)。
通過 inout,Swift 在保持值類型安全性的同時,提供了靈活的參數修改能力,是處理“需要函數修改外部變量”場景的核心工具。