Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

performance - Does a mutating struct function in swift create a new copy of self?

I like value semantics in swift but I am worried about the performance of mutating functions. Suppose we have the following struct

struct Point {
   var x = 0.0
   mutating func add(_ t:Double){
      x += t
   }
}

Now suppose we create a Point and mutate it as so:

var p = Point()
p.add(1)

Now does the existing struct in memory get mutated, or is self replaced with a new instance as in

self = Point(x:self.x+1)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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
    }
}

and suppose I create a new instance of this struct:

var p = Point(x: 1, y: 2)

This statically allocates some memory on the stack. It'll look something like this:

00000000  00000001  00000010  00000000
<------^  ^------^  ^------^ ^----->
other    | self.x | self.y | other memory
          ^----------------^
          the p struct

Let's see what will happen in both situations when we call p.add(x: 3):

  1. The existing struct is mutated in-place:

    Our struct in memory will look like this:

    00000000  00000100  00000010  00000000
    <------^  ^------^  ^------^ ^----->
    other    | self.x | self.y | other memory
            ^----------------^
            the p struct
    
  2. Self is replaced with a new instance:

    Our struct in memory will look like this:

    00000000  00000100  00000010  00000000
    <------^  ^------^  ^------^ ^----->
    other    | self.x | self.y | other memory
            ^----------------^
            the p struct
    

Notice that there's no difference between the two scenarios. That's because assigning a new value to self causes in-place mutation. p is always the same two bytes of memory on the stack. Assigning self a new value to p will only replace the contents of those 2 bytes, but it'll still be the same two bytes.

Now there can be one difference between the two scenarios, and that deals with any possible side effects of the initializer. Suppose this is our struct, instead:

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...