Struct中的mutating关键字
mutating:只用在值类型中
struct LGStack {
var items = [Int]()
func push(_ item: Int) {
items.append(item)
}
}
对于结构体而言,我创建了一个items的数组,而且给定LGStack一个push办法,向items数组内append元素,这个时分,会提示过错,很显然不允许我修正items!
mutating:只用在值类型中
struct LGStack {
var items = [Int]()
func push(_ item: Int) {
items.append(item)
}
}
对于结构体而言,我创建了一个items的数组,而且给定LGStack一个push办法,向items数组内append元素,这个时分,会提示过错,很显然不允许我修正items!
打开项目文件夹目录
cd /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice
把 mian.swift编译成main.sil并打开(推荐使用vs code)
swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil No application knows how to open /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice/main.sil.
经过main.si能够看到为什么:
// LGStack.push(_:)
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @guaranteed LGStack) -> () {
// %0 "item" // users: %11, %2
// %1 "self" // user: %3
bb0(%0 : $Int, %1 : $LGStack):
debug_value %0 : $Int, let, name "item", argno 1 // id: %2
debug_value %1 : $LGStack, let, name "self", argno 2 // id: %3
%4 = integer_literal $Builtin.Word, 1 // user: %6
// function_ref _allocateUninitializedArray<A>(_:)
%5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // user: %6
%6 = apply %5<Any>(%4) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // users: %8, %7
%7 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 0 // users: %20, %17
%8 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 1 // user: %9
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any // user: %10
%10 = init_existential_addr %9 : $*Any, $Int // user: %11
store %0 to %10 : $*Int // id: %11
// function_ref default argument 1 of print(_:separator:terminator:)
%12 = function_ref @default argument 1 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %13
%13 = apply %12() : $@convention(thin) () -> @owned String // users: %19, %17
// function_ref default argument 2 of print(_:separator:terminator:)
%14 = function_ref @default argument 2 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %15
%15 = apply %14() : $@convention(thin) () -> @owned String // users: %18, %17
// function_ref print(_:separator:terminator:)
%16 = function_ref @Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> () // user: %17
%17 = apply %16(%7, %13, %15) : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> ()
release_value %15 : $String // id: %18
release_value %13 : $String // id: %19
release_value %7 : $Array<Any> // id: %20
%21 = tuple () // user: %22
return %21 : $() // id: %22
} // end sil function 'main.LGStack.push(Swift.Int) -> ()'
debug_value %1 : $LGStack, let, name “self”, argno 2 // id: %3 首要push办法供给默许的参数self,这也是我能够在push办法内拜访到items的原因,那么self 便是 LGStack, 是用let进行润饰的,也便是说,是不可变的,这也便是报错的原因
也便是说我在修正items的时分,便是在修正LGStack自身,而且LGStack还是一个let,所以不允许!
经过mutating润饰之后
struct LGStack {
var items = [Int]()
mutating func push(_ item: Int) {
print(item)
items.append(item)
}
}
var s = LGStack()
s.push(1)
print(s.items)
lldb打印成果为
1
(lldb)
那么我在sil面看一下,mutating究竟做了什么:
// LGStack.push(_:)
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @inout LGStack) -> () {
// %0 "item" // users: %22, %11, %2
// %1 "self" // users: %23, %3
bb0(%0 : $Int, %1 : $*LGStack):
debug_value %0 : $Int, let, name "item", argno 1 // id: %2
debug_value_addr %1 : $*LGStack, var, name "self", argno 2 // id: %3
%4 = integer_literal $Builtin.Word, 1 // user: %6
// function_ref _allocateUninitializedArray<A>(_:)
%5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // user: %6
%6 = apply %5<Any>(%4) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // users: %8, %7
%7 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 0 // users: %20, %17
%8 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 1 // user: %9
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any // user: %10
%10 = init_existential_addr %9 : $*Any, $Int // user: %11
store %0 to %10 : $*Intice/SwiftTwoPractice
把 mian.swift编译成main.sil并打开(推荐使用vs code)
>swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil
No application knows how to open /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice/main.sil.
经过main.si能够看到为什么:
// LGStack.push(_:)
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @guaranteed LGStack) -> () {
// %0 "item" // users: %11, %2
// %1 "self" // user: %3
bb0(%0 : $Int, %1 : $LGStack):
debug_value %0 : $Int, let, name "item", argno 1 // id: %2
debug_value %1 : $LGStack, let, name "self", argno 2 // id: %3
%4 = integer_literal $Builtin.Word, 1 // user: %6
// function_ref _allocateUninitializedArray<A>(_:)
%5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // user: %6
%6 = apply %5<Any>(%4) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // users: %8, %7
%7 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 0 // users: %20, %17
%8 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 1 // user: %9
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any // user: %10
%10 = init_existential_addr %9 : $*Any, $Int // user: %11
store %0 to %10 : $*Int // id: %11
// function_ref default argument 1 of print(_:separator:terminator:)
%12 = function_ref @default argument 1 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %13
%13 = apply %12() : $@convention(thin) () -> @owned String // users: %19, %17
// function_ref default argument 2 of print(_:separator:terminator:)
%14 = function_ref @default argument 2 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %15
%15 = apply %14() : $@convention(thin) () -> @owned String // users: %18, %17
// function_ref print(_:separator:terminator:)
%16 = function_ref @Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> () // user: %17
%17 = apply %16(%7, %13, %15) : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> ()
release_value %15 : $String // id: %18
release_value %13 : $String // id: %19
release_value %7 : $Array<Any> // id: %20
%21 = tuple () // user: %22
return %21 : $() // id: %22
} // end sil function 'main.LGStack.push(Swift.Int) -> ()'
debug_value %1 : $LGStack, let, name “self”, argno 2 // id: %3 首要push办法供给默许的参数self,这也是我能够在push办法内拜访到items的原因,那么self 便是 LGStack, 是用let进行润饰的,也便是说,是不可变的,这也便是报错的原因
也便是说我在修正items的时分,便是在修正LGStack自身,而且LGStack还是一个let,所以不允许!
经过mutating润饰之后
struct LGStack {
var items = [Int]()
mutating func push(_ item: Int) {
print(item)
items.append(item)
}
}
var s = LGStack()
s.push(1)
print(s.items)
lldb打印成果为
1
(lldb)
那么我在sil面看一下,mutating究竟做了什么:
// LGStack.push(_:)
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @inout LGStack) -> () {
// %0 "item" // users: %22, %11, %2
// %1 "self" // users: %23, %3
bb0(%0 : $Int, %1 : $*LGStack):
debug_value %0 : $Int, let, name "item", argno 1 // id: %2
debug_value_addr %1 : $*LGStack, var, name "self", argno 2 // id: %3
%4 = integer_literal $Builtin.Word, 1 // user: %6
// function_ref _allocateUninitializedArray<A>(_:)
%5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // user: %6
%6 = apply %5<Any>(%4) : $@convention(thin) <_0_0> (Builtin.Word) -> (@owned Array<_0_0>, Builtin.RawPointer) // users: %8, %7
%7 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 0 // users: %20, %17
%8 = tuple_extract %6 : $(Array<Any>, Builtin.RawPointer), 1 // user: %9
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*Any // user: %10
%10 = init_existential_addr %9 : $*Any, $Int // user: %11
store %0 to %10 : $*Int // id: %11
// function_ref default argument 1 of print(_:separator:terminator:)
%12 = function_ref @default argument 1 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %13
%13 = apply %12() : $@convention(thin) () -> @owned String // users: %19, %17
// function_ref default argument 2 of print(_:separator:terminator:)
%14 = function_ref @default argument 2 of Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) () -> @owned String // user: %15
%15 = apply %14() : $@convention(thin) () -> @owned String // users: %18, %17
// function_ref print(_:separator:terminator:)
%16 = function_ref @Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> () // user: %17
%17 = apply %16(%7, %13, %15) : $@convention(thin) (@guaranteed Array<Any>, @guaranteed String, @guaranteed String) -> ()
release_value %15 : $String // id: %18
release_value %13 : $String // id: %19
release_value %7 : $Array<Any> // id: %20
%21 = alloc_stack $Int // users: %22, %28, %26
store %0 to %21 : $*Int // id: %22
%23 = begin_access [modify] [static] %1 : $*LGStack // users: %27, %24
%24 = struct_element_addr %23 : $*LGStack, #LGStack.items // user: %26
// function_ref Array.append(_:)
%25 = function_ref @Swift.Array.append(__owned A) -> () : $@convention(method) <_0_0> (@in _0_0, @inout Array<_0_0>) -> () // user: %26
%26 = apply %25<Int>(%21, %24) : $@convention(method) <_0_0> (@in _0_0, @inout Array<_0_0>) -> ()
end_access %23 : $*LGStack // id: %27
dealloc_stack %21 : $*Int // id: %28
%29 = tuple () // user: %30
return %29 : $() // id: %30
} // end sil function 'main.LGStack.push(Swift.Int) -> ()'
sil hidden @main.LGStack.push(Swift.Int) -> () : $@convention(method) (Int, @inout LGStack) -> () 特别关注这儿,给LGStack 添加了一个润饰符@inout(输入输出参数)
debug_value_addr %1 : $*LGStack, var, name “self”, argno 2 // id: %3 这儿的self的润饰符变成了var,变成了一个可变的self,而且self拜访的是一个地址debug_value_addr,而不是原始value的值了debug_value
本质上mutating这个关键字就做了一件事情,默许给结构体LGStack添加了一个intou关键字,这个inout关键字传递的过程中传递的便是所谓的引用
在函数的声明中,默许的参数都是不可变的
func swap(_ a: Int,_ b: Int) {
let temp = a
a = b
b = temp
}
这个代码会呈现报错:
说明默许参数是不可变的,想要可变,需要添加inout关键字
func swap(_ a: inout Int,_ b: inout Int) {
let temp = a
a = b
b = temp
}
var age = 10
var age2 = 30
//传递的是地址
swap(&age, &age2)
print(age)
print(age2)
这儿调用swap函数传递的是地址(&),也便是说inout关键字传递的是地址
注意:
- mutating:润饰的是办法
- inout:修正的是参数类型