我喜欢迅速地使用值语义,但是我担心变异函数的性能。假设我们有以下内容struct
struct Point {
var x = 0.0
mutating func add(_ t:Double){
x += t
}
}
现在,假设我们创建了一个Point
并对其进行了变异:
var p = Point()
p.add(1)
现在struct
,内存中的现有变量是否发生了突变,或者被self
替换为新的实例,如
self = Point(x:self.x+1)
现在,内存中的现有结构是否发生了突变,或者被新实例自行替换了?
从概念上讲,这两个选项是完全相同的。我将使用此示例结构,该结构使用UInt8而不是Double(因为它的位更易于可视化)。
struct Point {
var x: UInt8
var y: UInt8
mutating func add(x: UInt8){
self.x += x
}
}
并假设我为此结构创建了一个新实例:
var p = Point(x: 1, y: 2)
这会在堆栈上静态分配一些内存。它看起来像这样:
00000000 00000001 00000010 00000000
<------^ ^------^ ^------^ ^----->
other | self.x | self.y | other memory
^----------------^
the p struct
让我们看看在两种情况下调用时会发生什么p.add(x: 3)
:
现有的struct就地进行了突变:
我们在内存中的结构将如下所示:
00000000 00000100 00000010 00000000
<------^ ^------^ ^------^ ^----->
other | self.x | self.y | other memory
^----------------^
the p struct
将Self替换为新实例:
我们在内存中的结构将如下所示:
00000000 00000100 00000010 00000000
<------^ ^------^ ^------^ ^----->
other | self.x | self.y | other memory
^----------------^
the p struct
注意,这两种情况之间没有区别。那是因为给self赋一个新值会导致就地突变。p
在堆栈上始终是相同的两个字节的内存。为self分配新值p
只会替换这2个字节的内容,但仍将是相同的两个字节。
现在,两种情况之间可能存在一个差异,该差异处理了初始化程序的任何可能的副作用。假设这是我们的结构,而不是:
struct Point {
var x: UInt8
var y: UInt8
init(x: UInt8, y: UInt8) {
self.x = x
self.y = y
print("Init was run!")
}
mutating func add(x: UInt8){
self.x += x
}
}
运行时var p = Point(x: 1, y: 2)
,您会看到Init was run!
已打印出来(按预期)。但是,当您运行时p.add(x: 3)
,您会看到没有进一步打印。这告诉我们初始化器不是新的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句