web-dev-qa-db-ja.com

配列内の構造体の値を変更する

配列内に構造体を保存し、forループで構造体の値にアクセスして変更したい。

struct testing {
    var value:Int
}

var test1 = testing(value: 6 )

test1.value = 2
// this works with no issue

var test2 = testing(value: 12 )

var testings = [ test1, test2 ]

for test in testings{
    test.value = 3
// here I get the error:"Can not assign to 'value' in 'test'"
}

構造体をクラスに変更すると機能します。構造体の値を変更する方法を教えてください。

49
reza23

@MikeSが言ったことに加えて、構造体は値型であることを忘れないでください。 forループでは:

for test in testings {

配列要素のcopytest変数に割り当てられます。それに対して行う変更は、配列要素に実際の変更を加えることなく、test変数に制限されます。クラスは参照型であるため機能します。したがって、valueではなくreferencetestにコピーされます。変数。

これを行う適切な方法は、インデックスでforを使用することです。

for index in 0..<testings.count {
    testings[index].value = 15
}

この場合、実際のstruct要素にアクセス(および変更)し、そのコピーではありません。

68
Antonio

さて、Swift 3の互換性についての答えを更新します。

多くのプログラミングを行っている場合、コレクション内のオブジェクトの値を変更する必要があります。この例では、構造体の配列があり、特定のオブジェクトの値を変更する必要がある条件が与えられています。これは、開発の日に非常に一般的なことです。

どのオブジェクトを変更する必要があるかを判断するためにインデックスを使用する代わりに、私はif条件を使用することを好みます。

import Foundation

struct MyStruct: CustomDebugStringConvertible {
    var myValue:Int
    var debugDescription: String {
        return "struct is \(myValue)"
    }
}

let struct1 = MyStruct(myValue: 1)
let struct2 = MyStruct(myValue: 2)
let structArray = [struct1, struct2]

let newStructArray = structArray.map({ (myStruct) -> MyStruct in
    // You can check anything like:
    if myStruct.myValue == 1 {
        var modified = myStruct
        modified.myValue = 400
        return modified
    } else {
        return myStruct
    }
})

debugPrint(newStructArray)

この開発方法の方が安全です。

クラスは参照型であり、構造体の場合のように値を変更するためにコピーを作成する必要はありません。クラスで同じ例を使用する:

class MyClass: CustomDebugStringConvertible {
    var myValue:Int

    init(myValue: Int){
        self.myValue = myValue
    }

    var debugDescription: String {
        return "class is \(myValue)"
    }
}

let class1 = MyClass(myValue: 1)
let class2 = MyClass(myValue: 2)
let classArray = [class1, class2]

let newClassArray = classArray.map({ (myClass) -> MyClass in
    // You can check anything like:
    if myClass.myValue == 1 {
        myClass.myValue = 400
    }
    return myClass
})

debugPrint(newClassArray)
9
LightMan

配列内の値型の操作を簡素化するには、次の拡張機能(Swift 3)を使用できます。

extension Array {
    mutating func modifyForEach(_ body: (_ index: Index, _ element: inout Element) -> ()) {
        for index in indices {
            modifyElement(atIndex: index) { body(index, &$0) }
        }
    }

    mutating func modifyElement(atIndex index: Index, _ modifyElement: (_ element: inout Element) -> ()) {
        var element = self[index]
        modifyElement(&element)
        self[index] = element
    }
}

使用例:

testings.modifyElement(atIndex: 0) { $0.value = 99 }
testings.modifyForEach { $1.value *= 2 }
testings.modifyForEach { $1.value = $0 }
2

これは非常に難しい答えです。 このようにしてはいけません

struct testing {
    var value:Int
}

var test1 = testing(value: 6)
var test2 = testing(value: 12)

var ary = [UnsafeMutablePointer<testing>].convertFromArrayLiteral(&test1, &test2)

for p in ary {
    p.memory.value = 3
}

if test1.value == test2.value {
    println("value: \(test1.value)")
}

Xcode 6.1の場合、配列の初期化は

var ary = [UnsafeMutablePointer<testing>](arrayLiteral: &test1, &test2)
2
rintaro

私はアントニオの答えを試してみましたが、これはかなり論理的に思えましたが、驚いたことにうまくいきません。これをさらに調査して、次のことを試しました。

struct testing {
    var value:Int
}

var test1 = testing(value: 6 )
var test2 = testing(value: 12 )

var testings = [ test1, test2 ]

var test1b = testings[0]
test1b.value = 13

// I would assume this is same as test1, but it is not test1.value is still 6

// even trying 

testings[0].value = 23

// still the value of test1 did not change.
// so I think the only way is to change the whole of test1

test1 = test1b
0
reza23

十分な答えがあります。より一般的な角度から質問に取り組むだけです。

値の型とそれがコピーされることの意味をよりよく理解する別の例として:

struct Item {
    var value:Int
}
var item1 = Item(value: 5)

func testMutation ( item: Item){
    item.value = 10 //  cannot assign to property: 'item' is a 'let' constant 
}

それは、アイテムがコピーされ、入ったときに不変であるためです-便宜上。


func anotherTest (item : Item){
    print(item.value)
}

anotherTest(item: item1) // 5

突然変異は起こらないので、エラーはありません


var item2 = item1 // mutable copy created.
item2.value = 10
print(item2.value) // 10
print(item1.value) // 5
0
Honey

構造体の新しい配列を再作成することになりました。下の例を参照してください。

func updateDefaultCreditCard(token: String) {
    var updatedArray: [CreditCard] = []
    for aCard in self.creditcards {
        var card = aCard
        card.isDefault = aCard.token == token
        updatedArray.append(card)
    }
    self.creditcards = updatedArray
}
0
Nicolas Manzini