web-dev-qa-db-de.com

Ändern des Werts von struct in einem Array

Ich möchte Strukturen innerhalb eines Arrays speichern, auf die Werte der Struktur in einer for-Schleife zugreifen und sie ändern. 

struct testing {
    var value:Int
}

var test1 = testing(value: 6 )

test1.value = 2
// this works with no issue

var test2 = testing(value: 12 )

var testings = [ test1, test2 ]

for test in testings{
    test.value = 3
// here I get the error:"Can not assign to 'value' in 'test'"
}

Wenn ich die Struktur in Klasse umwandle, funktioniert es. Kann mir jemand sagen, wie ich den Wert der Struktur ändern kann.

45
reza23

Denken Sie daran, dass es sich bei den Strukturen um Werttypen handelt. Also in der for Schleife:

for test in testings {

ein copy eines Array-Elements wird der Variablen test zugewiesen. Jede Änderung, die Sie daran vornehmen, ist auf die Variable test beschränkt, ohne die Array-Elemente tatsächlich zu ändern. Es funktioniert für Klassen, da es sich um Referenztypen handelt. Daher wird reference und nicht value in die Variable test kopiert.

Der richtige Weg, dies zu tun, ist die Verwendung einer for nach Index:

for index in 0..<testings.count {
    testings[index].value = 15
}

in diesem Fall greifen Sie auf das eigentliche Strukturelement zu (und ändern es nicht) und nicht auf eine Kopie davon.

62
Antonio

Nun, ich werde meine Antwort auf die Kompatibilität mit Swift 3 aktualisieren.

Wenn Sie viele programmieren, müssen Sie einige Werte von Objekten ändern, die sich in einer Sammlung befinden. In diesem Beispiel haben wir ein Array von struct und unter der Bedingung, dass wir den Wert eines bestimmten Objekts ändern müssen. Dies ist eine sehr gewöhnliche Sache an jedem Entwicklungstag.

Anstatt einen Index zu verwenden, um zu bestimmen, welches Objekt geändert werden muss, bevorzuge ich die Verwendung einer if-Bedingung.

import Foundation

struct MyStruct: CustomDebugStringConvertible {
    var myValue:Int
    var debugDescription: String {
        return "struct is \(myValue)"
    }
}

let struct1 = MyStruct(myValue: 1)
let struct2 = MyStruct(myValue: 2)
let structArray = [struct1, struct2]

let newStructArray = structArray.map({ (myStruct) -> MyStruct in
    // You can check anything like:
    if myStruct.myValue == 1 {
        var modified = myStruct
        modified.myValue = 400
        return modified
    } else {
        return myStruct
    }
})

debugPrint(newStructArray)

Beachten Sie alle Möglichkeiten, diese Art der Entwicklung ist sicherer.

Bei den Klassen handelt es sich um Referenztypen. Es ist nicht erforderlich, eine Kopie zu erstellen, um einen Wert zu ändern. Dasselbe Beispiel mit Klassen verwenden:

class MyClass: CustomDebugStringConvertible {
    var myValue:Int

    init(myValue: Int){
        self.myValue = myValue
    }

    var debugDescription: String {
        return "class is \(myValue)"
    }
}

let class1 = MyClass(myValue: 1)
let class2 = MyClass(myValue: 2)
let classArray = [class1, class2]

let newClassArray = classArray.map({ (myClass) -> MyClass in
    // You can check anything like:
    if myClass.myValue == 1 {
        myClass.myValue = 400
    }
    return myClass
})

debugPrint(newClassArray)
7
LightMan

Um das Arbeiten mit Werttypen in Arrays zu vereinfachen, können Sie folgende Erweiterung (Swift 3) verwenden:

extension Array {
    mutating func modifyForEach(_ body: (_ index: Index, _ element: inout Element) -> ()) {
        for index in indices {
            modifyElement(atIndex: index) { body(index, &$0) }
        }
    }

    mutating func modifyElement(atIndex index: Index, _ modifyElement: (_ element: inout Element) -> ()) {
        var element = self[index]
        modifyElement(&element)
        self[index] = element
    }
}

Verwendungsbeispiel:

testings.modifyElement(atIndex: 0) { $0.value = 99 }
testings.modifyForEach { $1.value *= 2 }
testings.modifyForEach { $1.value = $0 }
2

Das ist eine sehr knifflige Antwort. Ich denke, Sie sollten das nicht machen :

struct testing {
    var value:Int
}

var test1 = testing(value: 6)
var test2 = testing(value: 12)

var ary = [UnsafeMutablePointer<testing>].convertFromArrayLiteral(&test1, &test2)

for p in ary {
    p.memory.value = 3
}

if test1.value == test2.value {
    println("value: \(test1.value)")
}

Für Xcode 6.1 wird die Array-Initialisierung sein

var ary = [UnsafeMutablePointer<testing>](arrayLiteral: &test1, &test2)
2
rintaro

Ich probierte die Antwort von Antonio, die ziemlich logisch erschien, aber zu meiner Überraschung klappt es nicht. Um dies weiter zu erforschen, versuchte ich Folgendes:

struct testing {
    var value:Int
}

var test1 = testing(value: 6 )
var test2 = testing(value: 12 )

var testings = [ test1, test2 ]

var test1b = testings[0]
test1b.value = 13

// I would assume this is same as test1, but it is not test1.value is still 6

// even trying 

testings[0].value = 23

// still the value of test1 did not change.
// so I think the only way is to change the whole of test1

test1 = test1b
0
reza23

Sie haben genug gute Antworten. Ich werde die Frage nur aus einem allgemeineren Blickwinkel angehen.

Als weiteres Beispiel für ein besseres Verständnis der Werttypen und deren Bedeutung werden sie kopiert:

struct Item {
    var value:Int
}
var item1 = Item(value: 5)

func testMutation ( item: Item){
    item.value = 10 //  cannot assign to property: 'item' is a 'let' constant 
}

Das ist, weil Artikel kopiert werden, wenn sie hereinkommen, ist sie unveränderlich - als Bequemlichkeit.  


func anotherTest (item : Item){
    print(item.value)
}

anotherTest(item: item1) // 5

Es tritt keine Mutation auf, also kein Fehler


var item2 = item1 // mutable copy created.
item2.value = 10
print(item2.value) // 10
print(item1.value) // 5
0
Honey

Ich habe am Ende ein neues Array von struct erstellt, siehe das Beispiel unten.

func updateDefaultCreditCard(token: String) {
    var updatedArray: [CreditCard] = []
    for aCard in self.creditcards {
        var card = aCard
        card.isDefault = aCard.token == token
        updatedArray.append(card)
    }
    self.creditcards = updatedArray
}
0
Nicolas Manzini