我很喜欢迅速的价值观调子,但我担心变体功能的履行。 附录
struct Point {
var x = 0.0
mutating func add(_ t:Double){
x += t
}
}
如今,我们建立了<条码><><>>>>>,并做了改动:
var p = Point()
p.add(1)
现在,记忆中现有的<条码>条码>已变,或<条码>自封/条码>改为新例,如上所示。
self = Point(x:self.x+1)
我很喜欢迅速的价值观调子,但我担心变体功能的履行。 附录
struct Point {
var x = 0.0
mutating func add(_ t:Double){
x += t
}
}
如今,我们建立了<条码><><>>>>>,并做了改动:
var p = Point()
p.add(1)
现在,记忆中现有的<条码>条码>已变,或<条码>自封/条码>改为新例,如上所示。
self = Point(x:self.x+1)
Now does the existing struct in memory get mutated, or is self replaced with a new instance
Conceptually, these two options are exactly the same. I ll use this example struct, which uses UInt8 instead of Double (because its bits are easier to visualize).
struct Point {
var x: UInt8
var y: UInt8
mutating func add(x: UInt8){
self.x += x
}
}
我提出了这一结构的新例子:
var p = Point(x: 1, y: 2)
静态地把一些记忆放在 st上。 它看着这样的情况:
00000000 00000001 00000010 00000000
<------^ ^------^ ^------^ ^----->
other |self.x | self.y | other memory
^----------------^
the p struct
让我们看看在这两种情况下会发生什么情况,我们称之为<编码>p.add(x:3):
现有结构在内部变换:
我们的记忆将照此办理:
00000000 00000100 00000010 00000000
<------^ ^------^ ^------^ ^----->
other | self.x | self.y | other memory
^----------------^
the p struct
自我取而代之的是新情况:
我们的记忆将照此办理:
00000000 00000100 00000010 00000000
<------^ ^------^ ^------^ ^----->
other | self.x | self.y | other memory
^----------------^
the p struct
通知说两种情况之间没有差别。 这是因为将新价值分配给内部的自行成因。 <代码>p总是在记分栏上用同样的两个字标。 将自己的新价值转让给<代码>p<>>>/code>将只会以斜体取代这2条内容,但仅用同一两条 by。
现在,can是两种假设情景之间的一种区别,涉及初始使用人的任何可能的副作用。 证明这一点是我们的方向,而是:
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
}
}
When you run var p = Point(x: 1, y: 2)
, you ll see that Init was run!
is printed (as expected). But when you run p.add(x: 3)
, you ll see that nothing further is printed. This tells us that the initializer is not anew.
I feel it s worth taking a look (from a reasonably high-level) at what the compiler does here. If we take a look at the canonical SIL emitted for:
struct Point {
var x = 0.0
mutating func add(_ t: Double){
x += t
}
}
var p = Point()
p.add(1)
We can see that the add(_:)
method gets emitted as:
// Point.add(Double) -> ()
sil hidden @main.Point.add (Swift.Double) -> () :
$@convention(method) (Double, @inout Point) -> () {
// %0 // users: %7, %2
// %1 // users: %4, %3
bb0(%0 : $Double, %1 : $*Point):
// get address of the property x within the point instance.
%4 = struct_element_addr %1 : $*Point, #Point.x, loc "main.swift":14:9, scope 5 // user: %5
// get address of the internal property _value within the Double instance.
%5 = struct_element_addr %4 : $*Double, #Double._value, loc "main.swift":14:11, scope 5 // users: %9, %6
// load the _value from the property address.
%6 = load %5 : $*Builtin.FPIEEE64, loc "main.swift":14:11, scope 5 // user: %8
// get the _value from the double passed into the method.
%7 = struct_extract %0 : $Double, #Double._value, loc "main.swift":14:11, scope 5 // user: %8
// apply a builtin floating point addition operation (this will be replaced by an fadd instruction in IR gen).
%8 = builtin "fadd_FPIEEE64"(%6 : $Builtin.FPIEEE64, %7 : $Builtin.FPIEEE64) : $Builtin.FPIEEE64, loc "main.swift":14:11, scope 5 // user: %9
// store the result to the address of the _value property of x .
store %8 to %5 : $*Builtin.FPIEEE64, loc "main.swift":14:11, scope 5 // id: %9
%10 = tuple (), loc "main.swift":14:11, scope 5
%11 = tuple (), loc "main.swift":15:5, scope 5 // user: %12
return %11 : $(), loc "main.swift":15:5, scope 5 // id: %12
} // end sil function main.Point.add (Swift.Double) -> ()
xcrun Immediatec -emit-sil main.swift ×crun Immediate-demangle > main.silgen
The important thing here is how Swift treats the implicit self
parameter. You can see that it s been emitted as an @inout
parameter, meaning that it ll be passed by reference into the function.
In order to perform the mutation of the x
property, the struct_element_addr
SIL instruction is used in order to lookup its address, and then the underlying _value
property of the Double
. The resultant double is then simply stored back at that address with the store
instruction.
这意味着,<代码>add(_:>”方法能够直接改变记忆中<代码>p<>/code>x 的财产的价值,而不造成任何中间的<代码><><>>>>>>>>>。
我这样做了:
import Foundation
struct Point {
var x = 0.0
mutating func add(_ t:Double){
x += t
}
}
var p = Point()
withUnsafePointer(to: &p) {
print("(p) has address: ($0)")
}
p.add(1)
withUnsafePointer(to: &p) {
print("(p) has address: ($0)")
}
产出:
点(x:0.0)有地址: 0x000000010fc2fb80
Point(x:1.0)有地址: 0x000000010fc2fb80
鉴于记忆地址没有改变,我必须改变方向,而不是取而代之。
为了完全取而代之,你必须使用另一个记忆地址,因此在原始记忆地址复制该物体是毫无意义的。
或许通过这种思路更容易理解,即使结构已变,因为其价值类型不同,新价值与旧价值不同,因此,根据价值类型的定义,它们是不同的。
How can I initialize this nested struct in C? typedef struct _s0 { int size; double * elems; }StructInner ; typedef struct _s1 { StructInner a, b, c, d, e; long f; char[16] s; }...
I m trying to write some reasonably generic networking code. I have several kinds of packets, each represented by a different struct. The function where all my sending occurs looks like: - (void)...
Purpose I am writing a network program in C (specifically gnu89) and I would like to simplify things by reinterpreting a certain struct X as big array of bytes (a.k.a. char), sending the bytes over ...
I m using auto-implemented properties. I guess the fastest way to fix following is to declare my own backing variable? public Point Origin { get; set; } Origin.X = 10; // fails with CS1612 Error ...
I have a client and server program where I want to send an entire struct from the client and then output the struct member "ID" on the server. I have done all the connecting etc and already managed ...
Assume I have a such struct: (define-struct node (value next)) ;and making 2 nodes, parent pointing to child as next. (define child (make-node 2 null)) (define parent (make-node 1 child)) Under ...
struct Div { int i; int j; }; class A { public: A(); Div& divs; }; In my constructor definition, I have the following implementation A::A(): divs(NULL) {} I get the following ...
The following code prints (when invoking MyMethod): 0 0 0 1 I would expect it to print: 0 0 1 1 Why is this? Code: private struct MyStruct { public MyInnerStruct innerStruct; } private ...