構造体の配列の要素への参照を作成することは可能ですか?

Aug 19 2020

与えられたArraystruct

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

次の操作では、元の配列要素は変更されません

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

次の操作は、元の配列要素を変更します

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

    print(cards[0].flag)

ただし、その意味では効率的ではなく、毎回インデックスアクセスを実行する必要があります。想像してみてください

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

構造体の配列の要素への参照を作成する方法はありますか?私たちが書くことができるように

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

可能性の1つは、に置き換えるstructことclassです。しかし、そうする前に、他の選択肢を模索したいと思います。

回答

7 gcharita Aug 19 2020 at 11:25

関数を使用して変更を加え、次のCardように参照によって構造体を渡すことで、これを実現できます。

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

または、Cardタイプでミューティング関数を使用し、クロージャとして次のように変更を渡すことで、さらに良い結果が得られます。

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

更新:2番目のアプローチをさらに再利用可能にするために、次のようなプロトコルを定義できます。

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

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

そして作るCard構造体がそれに準拠:

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

その後、上記のように使用できます。

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

Arrayis astructstructsは値型であるため、これは予想される動作です。

あなたを変換する必要がありますので、何が必要、参照型の動作ですstructclass

値型のいくつかのプロパティを一度に変更するための別の解決策は、それを行うmutating関数を作成し、それを配列要素で呼び出すことです。

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