เป็นไปได้ไหมที่จะสร้างการอ้างอิงถึงองค์ประกอบของอาร์เรย์ของโครงสร้าง

Aug 19 2020

ให้Arrayด้วยstruct

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

หนึ่งในความเป็นไปได้คือการแทนที่ด้วย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"
}

อัปเดต : เพื่อให้แนวทางที่สองสามารถนำกลับมาใช้ใหม่ได้มากขึ้นคุณสามารถกำหนดโปรโตคอลดังนี้:

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

นี่คือลักษณะการทำงานที่คาดไว้เนื่องจากArrayเป็น a structและstructs เป็นประเภทค่า

สิ่งที่คุณต้องการคือพฤติกรรมประเภทอ้างอิงดังนั้นคุณควรแปลง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")