是否有可能创建对struct数组元素的引用?

问题描述

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

有没有办法创建对struct数组元素的引用?这样我们就可以编写

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

一种可能性是将struct替换为class。但是,在此之前,我想探索其他选择。

解决方法

您可以使用函数进行更改并通过引用传递Delphi结构,如下所示:

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

并使protocol Updatable { mutating func update(block: (inout Self) -> Void) } extension Updatable { mutating func update(block: (inout Self) -> Void) { block(&self) } } 结构符合它:

Card

然后您可以像上面一样使用它。

,

这是预期的行为,因为Arraystruct,而struct是值类型。

您需要的是引用类型的行为,因此您应该将struct转换为class

另一种一次性修改值类型的多个属性的解决方案是创建一个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")