Est-il jamais possible de créer une référence à l'élément du tableau de la structure?

Aug 19 2020

Étant donné un Arrayavecstruct

    import Foundation
    
    struct Card {
        var flag: String = ""
    }
    
    var cards = Array<Card>()
    cards.append(Card())

L'opération suivante ne modifiera PAS l'élément d'origine du tableau

    // A copy is created.
    var cardCopy = cards[0]
    
    // Will NOT modify cards[0] 
    cardCopy.flag = "modify0"
    
    print(cards[0].flag)

L'opération suivante modifiera l'élément original du tableau

    // We can modify cards[0] by
    cards[0].flag = "modify"

    print(cards[0].flag)

Cependant, ce n'est pas efficace dans le sens où nous devons effectuer un accès d'indexation à chaque fois. Imaginer

    cards[0].flag0 = "modify"
    cards[0].flag1 = "modify"
    cards[0].flag2 = "modify"
    cards[0].flag3 = "modify"
    ...

Y a-t-il un moyen, nous pouvons créer une référence à l'élément du tableau de la structure? Pour que nous puissions écrire

// How to create a reference to cards[0]?
var cardReference = ...
    cardReference.flag0 = "modify"
    cardReference.flag1 = "modify"
    cardReference.flag2 = "modify"
    cardReference.flag3 = "modify"
    ...

L'une des possibilités est de remplacer structpar class. Mais j'aimerais explorer une autre alternative, avant de le faire.

Réponses

7 gcharita Aug 19 2020 at 11:25

Vous pouvez y parvenir en utilisant une fonction pour apporter vos modifications et passer la Cardstructure par référence comme ceci:

func update(card: inout Card) {
    card.flag0 = "modify"
    card.flag1 = "modify"
    card.flag2 = "modify"
    card.flag3 = "modify"
}

var cards = Array<Card>()
cards.append(Card())

update(card: &cards[0])

ou encore mieux en utilisant une fonction de mutation dans le Cardtype et en passant comme fermeture vos changements comme ça:

struct Card {
    var flag0: String = ""
    var flag1: String = ""
    var flag2: String = ""
    var flag3: String = ""
    
    mutating func update(block: (inout Card) -> Void) {
        block(&self)
    }
}
    
var cards = Array<Card>()
cards.append(Card())

cards[0].update {
    $0.flag0 = "modify" $0.flag1 = "modify"
    $0.flag2 = "modify" $0.flag3 = "modify"
}

Mise à jour : pour rendre la deuxième approche encore plus réutilisable, vous pouvez définir un protocole comme celui-ci:

protocol Updatable {
    mutating func update(block: (inout Self) -> Void)
}

extension Updatable {
    mutating func update(block: (inout Self) -> Void) {
        block(&self)
    }
}

et rendez Cardstruct conforme à lui:

struct Card: Updatable {
    var flag0: String = ""
    var flag1: String = ""
    var flag2: String = ""
    var flag3: String = ""
}

Ensuite, vous pouvez l'utiliser comme ci-dessus.

DávidPásztor Aug 19 2020 at 11:16

C'est le comportement attendu, car Arrayest a structet structs sont des types valeur.

Ce dont vous avez besoin est un comportement de type référence, vous devez donc convertir votre fichier structen class.

Une autre solution pour modifier plusieurs propriétés d'un type valeur en une seule fois consiste à créer une mutatingfonction qui fait cela et à l'appeler sur l'élément de tableau.

struct Card {
    var flag: String = ""
    var flag2 = ""

    mutating func update(flag: String, flag2: String) {
        self.flag = flag
        self.flag2 = flag2
    }
}

var cards = [Card(flag: "a", flag2: "b")]
cards[0].update(flag: "b", flag2: "c")