5月27日 11:52
Swift inout 参数是什么?有什么限制和使用场景?
inout 让函数直接修改传入的变量。默认情况下函数参数是常量(let),不能修改。加 inout 后,函数可以修改参数值,修改会写回原变量。调用时在变量前加 &:swap(&a, &b)。
inout 不是真正的引用传递——它的工作方式是"拷入-修改-拷出":函数调用时拷贝值进参数,函数内部修改,返回时拷贝回原变量。效果等价于引用传递,但实现不同。
追问
inout 和引用传递有什么区别?
Swift 没有真正的引用传递(除了 class 本身就是引用类型)。inout 是拷入拷出语义——函数拿到的是拷贝,修改后写回。这意味着函数内部对 inout 参数的修改不会影响其他指向同一变量的引用。实际效果和引用传递很像,但不是一回事。
inout 有什么限制?
不能传常量(let)或字面量——必须是 var。不能传计算属性——因为计算属性没有存储空间让函数写回。不能传有属性观察器(willSet/didSet)的属性——因为拷出时会触发观察器,但函数内部的修改不是通过正常的赋值路径。同一个函数调用中,同一个变量不能作为多个 inout 参数传入。
什么时候该用 inout?
极少用。Swift 风格更倾向返回新值而不是就地修改。合理场景:swap 函数、reduce 的 accumulator 模式、性能敏感场景避免大值拷贝。如果一个函数需要"返回多个值",优先用元组返回值,不要用多个 inout 参数。
inout 参数能传给另一个 inout 函数吗?
不能直接传——同一个变量不能同时作为两个 inout 参数。但可以在第一个 inout 函数返回后,把修改后的变量传给第二个函数。这个限制是为了防止两个函数同时修改同一个变量,导致结果不可预测。
写段代码
swiftfunc swap<T>(_ a: inout T, _ b: inout T) { let temp = a; a = b; b = temp } var x = 10, y = 20 swap(&x, &y) // x=20, y=10 // 累加器模式 func accumulate(_ value: Int, into total: inout Int) { total += value } var sum = 0 accumulate(5, into: &sum) // sum=5 accumulate(10, into: &sum) // sum=15 // 错误用法 // let a = 5; modify(&a) // 编译错误:a 是 let // modify(&view.frame.width) // 编译错误:frame 是计算属性