如果在类中使用mutating
关键字,编译器会报错'mutating' isn't valid on methods in classes or class-bound protocols
。
因为类是引用类型,而结构体和枚举是值类型,在值类型的实例方法中,值类型的属性默认是不可以被修改的。为了修改值类型的属性值,需要在它的实例方法上使用mutating
关键字。
struct LSStack {
private var items = [Int]()
mutating func push(item: Int) {
items.append(item)
}
}
var s = LSStack()
s.push(item: 1)
上面是一个简单的栈的例子,需要改变值类型LSStack
中属性items
的值,则需要在push
方法前添加mutating
关键字。
// LSStack.push(item:)
sil hidden @$s4main7LSStackV4push4itemySi_tF : $@convention(method) (Int, @inout LSStack) -> () {
// %0 "item" // users: %5, %2
// %1 "self" // users: %6, %3
bb0(%0 : $Int, %1 : $*LSStack):
debug_value %0 : $Int, let, name "item", argno 1 // id: %2
debug_value_addr %1 : $*LSStack, var, name "self", argno 2 // id: %3
%4 = alloc_stack $Int // users: %5, %11, %9
store %0 to %4 : $*Int // id: %5
%6 = begin_access [modify] [static] %1 : $*LSStack // users: %10, %7
%7 = struct_element_addr %6 : $*LSStack, #LSStack.items // user: %9
// function_ref Array.append(_:)
%8 = function_ref @$sSa6appendyyxnF : $@convention(method) <τ_0_0> (@in τ_0_0, @inout Array<τ_0_0>) -> () // user: %9
%9 = apply %8<Int>(%4, %7) : $@convention(method) <τ_0_0> (@in τ_0_0, @inout Array<τ_0_0>) -> ()
end_access %6 : $*LSStack // id: %10
dealloc_stack %4 : $*Int // id: %11
%12 = tuple () // user: %13
return %12 : $() // id: %13
} // end sil function '$s4main7LSStackV4push4itemySi_tF'
将上述代码转为sil
发现,push
参数中除了第一个显示的Int
类型参数,还有一个使用@inout
修饰的LSStack
,通过结构体元素地址进行修改。
func swap( a: inout Int, b: inout Int) {
let temp : Int = a
a = b
b = temp
}
var a:Int = 10
var b:Int = 20
swap(&a, &b)
print(a)
print(b)
函数参数默认是不可变,如果想要修改函数参数则需要使用inout
进行修饰,同时传参时需要传入地址