Apakah mungkin untuk membuat referensi ke elemen array struct?

Aug 19 2020

Diberikan Arraydenganstruct

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

Operasi berikut TIDAK akan mengubah elemen array asli

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

Operasi berikut akan mengubah elemen array asli

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

    print(cards[0].flag)

Namun, ini tidak efisien dalam artian, kami perlu melakukan akses pengindeksan setiap saat. Membayangkan

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

Adakah cara agar kita bisa membuat referensi ke elemen array struct? Agar kita bisa menulis

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

Salah satu kemungkinannya adalah dengan mengganti structdengan class. Tapi, saya ingin mencari alternatif lain, sebelum melakukannya.

Jawaban

7 gcharita Aug 19 2020 at 11:25

Anda dapat mencapainya menggunakan fungsi untuk membuat perubahan dan meneruskan Cardstruct dengan referensi seperti ini:

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])

atau bahkan lebih baik dengan menggunakan fungsi mutasi dalam Cardtipe dan meneruskan sebagai penutup perubahan Anda seperti itu:

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

Pembaruan : Untuk membuat pendekatan kedua lebih dapat digunakan kembali, Anda dapat menentukan protokol seperti ini:

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

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

dan buat Cardstruct sesuai dengan itu:

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

Kemudian Anda bisa menggunakannya seperti di atas.

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

Ini adalah perilaku yang diharapkan, karena Arrayadalah a structdan structs adalah tipe nilai.

Yang Anda butuhkan adalah perilaku tipe referensi, jadi Anda harus mengonversinya structmenjadi class.

Solusi lain untuk mengubah beberapa properti dari tipe nilai sekaligus adalah membuat mutatingfungsi yang melakukan itu dan memanggilnya pada elemen array.

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