简体   繁体   中英

Mutating arrays in a nested Swift struct

I'm new to Swift, so I appreciate any feedback or suggestions on my approach. For reference, I'm using Xcode 12.1 and Swift 5.3. Essentially, I have a series of struct s, one of which has an array of strings. What I'd like to do, is to append a string to that array. Consider the following code:

struct Collection {
    var things: [Thing] = []
    
    mutating func add(_ thing: Thing) {
        things.append(thing)
    }
}

struct Thing {
    var messages: [String] = []

    mutating func add(_ message: String) {
        messages.append(message)
    }
}

var collection = Collection()
collection.add(Thing())
var thing = collection.things.first
thing!.add("test")


print(collection.things.first!.messages.count)

I was expecting the final line to print 1 , but instead it prints 0 ! The compile does not display any errors either. If I change the code so that struct Thing is class Thing and drop the mutating keyword from its add method, then the code works.

Having said that, I don't understand why my original code does not work as I would expect. I'm able to append a Thing instance to Collection , but not a string to that same Thing instance after the fact.

Have I misunderstood how the mutating keyword works?

You would get your expected 1 if you did:

print(thing!.messages.count)

because you have added the "test" to thing.messages , not collection.things.first!.messages .

"Now hold on a second!" I hear you say, "I just said var thing = collection.things.first on the previous line! How come adding to thing.messages doesn't imply adding to collection.things.first!.messages ?".

This is because structs have value semantics. When you do var thing = collection.things.first , you are saying "copy the value of collection.things.first to a variable called thing ". You are not saying "the variable thing now refers to the same thing as collection.things.first ". To say that, Thing has to be a reference type ( class ).

So now you have two copies of the same value, one in thing and one in collection.things.first . You change the copy stored in thing . The other copy is unaffected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM