http://stackoverflow.com/questions/38422781/mutating-keyword-for-function-not-needed
Modifying Value Types from Within Instance Methods
Structures and enumerations are value types. When assigning a variable onto a value type, Value types are copied. Thus, after the assignment, the two variables have their own value type object. By default, the properties of a value type cannot be modified from within its instance methods. (http://chineseruleof8.com/code/index.php/2017/02/04/value-types-vs-reference-types/)
However, in a value type, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.
You can opt in to this behavior by placing the mutating keyword before the func keyword for that method …
Hence, we need to include the keyword mutating to allow a member (e.g. a function†) of a value type to mutate its members (e.g. the member properties of a struct).
Mutating a member of a value type instance means mutating the value type instance itself (self). The address will change.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// a value type struct Bill { let amount: Float private var _billedTo: Person // 1, points to reference type, shared by many references // 2, use (property name)ForRead to implement, read operations var billedToForRead: Person { print("-- billedToForRead --") return _billedTo } // 3, use (property name)ForWrite to implement, write operations var billedToCreateNewInstance: Person { // in a value type, if you need to modify the properties of your structure // or enumeration within a particular method, you can opt in to mutating behavior // for that method. // (our case) // Mutating a "member of a value type instance" means mutating the value type instance itself (self). // The address will change. mutating get { print("-- billedToForWrite --") print("\(_billedTo)") _billedTo = Person(name: _billedTo.name, address: _billedTo.address) return _billedTo } } init(amount: Float, billedTo: Person) { print("--- init Bill ---") self.amount = amount _billedTo = Person(name: billedTo.name, address: billedTo.address) } } var ricky = Person(name: "Ricky Tsao", address: "Shenzhen, China") var billOne = Bill(amount: 8.88, billedTo: ricky) var check = billOne.billedToForRead var newPerson = billOne.billedToCreateNewInstance print("------ END --------") |
So the situation of the code is that object Person “ricky” is allocated on the heap. Then the reference is passed into an object of type Bill. Inside the init for the object Bill, it instantiate a new Person object, and copies the data of the “ricky” Person. Thus, this ensures that our Bill object has its own Person object, initiated with data from “ricky” Person object. Thus, when changes in Bill object, it won’t touch the outside “ricky” Person object.
Whereas mutating a member of a reference type instance will not mean the reference of the reference type instance (which is considered self) is mutated. The address stays same.
Hence, since a class is a reference type in Swift, we need not include the mutating keyword in any of the instance methods of your Zombie class, even if they mutate the instance members or the class. If we were to speak of mutating the actual class instance fredTheZombie, we would refer to mutating its actual reference (e.g. to point at another Zombie instance).
[†]: As another example, we may use e.g. mutating getters (get); in which case we need to mark this explicitly as these are nonmutating by default. Setters (set), on the other hand, are mutating by default, and hence need no mutating keyword even if they mutate members of a value type.
Not good. Not readable
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct Counter { let count: Int init(count: Int = 0) { self.count = count } // the functional approach func counterByIncrementing() -> Counter { let newCount = count + 1 return Counter(count: newCount) } } |
1 2 |
var counter = Counter() counter = counter.counterByIncrementing() |
Let’s use mutating keyword – Much Better!
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct Counter { // this now has to be a var :/ var count: Int init(count: Int = 0) { self.count = count } // the mutating keyword approach mutating func increment() { count += 1 } } |