web-dev-qa-db-fra.com

Changer la valeur de struct dans un tableau

Je veux stocker des structures dans un tableau, accéder et modifier les valeurs de la structure dans une boucle for. 

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

Si je change la structure en classe cela fonctionne. Quelqu'un peut-il me dire comment je peux changer la valeur de la structure.

45
reza23

Outre ce que dit @MikeS, rappelez-vous que les structures sont des types de valeur. Donc dans la boucle for:

for test in testings {

un copy d'un élément de tableau est affecté à la variable test. Toute modification que vous apportez à celle-ci est limitée à la variable test, sans aucune modification réelle des éléments du tableau. Cela fonctionne pour les classes car ce sont des types de référence, donc reference et non pas value est copié dans la variable test.

Pour ce faire, utilisez une variable for by:

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

dans ce cas, vous accédez (et modifiez) l'élément struct réel et non une copie de celui-ci.

62
Antonio

Eh bien, je vais mettre à jour ma réponse pour la compatibilité Swift 3.

Lorsque vous en programmez plusieurs, vous devez modifier certaines valeurs d'objets se trouvant dans une collection. Dans cet exemple, nous avons un tableau de struct et, étant donné une condition, nous devons changer la valeur d'un objet spécifique. Ceci est une chose très commune dans n'importe quel jour de développement.

Au lieu d'utiliser un index pour déterminer quel objet doit être modifié, je préfère utiliser une condition if, qui est le plus commun.

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)

Notez toutes les possibilités, cette méthode de développement est plus sûre.

Les classes sont des types de référence, il n'est pas nécessaire de faire une copie pour changer une valeur, comme cela arrive avec les structures. En utilisant le même exemple avec les classes:

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

Pour simplifier l'utilisation des types de valeur dans les tableaux, vous pouvez utiliser l'extension suivante (Swift 3):

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

Exemple d'utilisation:

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

C'est une réponse très délicate. Je pense, Tu ne devrais pas faire comme ça :

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

Pour Xcode 6.1, l’initialisation du tableau sera

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

J'ai essayé la réponse d'Antonio qui semblait assez logique, mais à ma grande surprise, cela ne fonctionne pas. En explorant cela plus loin, j'ai essayé ce qui suit:

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

Vous en avez assez de bonnes réponses. Je vais juste aborder la question sous un angle plus générique.

Voici un autre exemple permettant de mieux comprendre les types de valeur et leur signification: ils sont copiés:

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 
}

C'est parce que l'élément est copié, quand il entre, il est immuable - par commodité.  


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

anotherTest(item: item1) // 5

Aucune mutation ne se produit, donc pas d'erreur


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

J'ai fini par recréer un nouveau tableau de struct, voir l'exemple ci-dessous.

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