2014-10-14 71 views
35

Tôi muốn lưu trữ các cấu trúc bên trong một mảng, truy cập và thay đổi các giá trị của cấu trúc trong vòng lặp for.Thay đổi Giá trị của struct trong một mảng

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

Nếu tôi thay đổi cấu trúc thành lớp hoạt động. Bất cứ ai có thể cho tôi biết làm thế nào tôi có thể thay đổi giá trị của struct.

+0

Xem thêm [loại giá trị so với loại lớp] (http://stackoverflow.com/a/41353620/5175709) Rob nói chính xác: * nếu bạn chuyển loại giá trị làm tham số cho phương thức một cái gì đó trên một chủ đề khác, về cơ bản bạn đang làm việc với một ** bản sao ** của loại giá trị đó. Điều này đảm bảo tính toàn vẹn của đối tượng đó được truyền cho phương thức. * – Honey

Trả lời

46

Bên cạnh những gì được nói bởi @MikeS, hãy nhớ rằng cấu trúc là các loại giá trị. Vì vậy, trong for loop:

for test in testings { 

một bản sao của một phần tử mảng được gán vào biến test. Bất kỳ thay đổi nào bạn thực hiện trên nó bị giới hạn ở biến số test, mà không thực hiện bất kỳ thay đổi thực tế nào đối với các phần tử mảng. Nó hoạt động cho các lớp vì chúng là các kiểu tham chiếu, do đó tham chiếu và không phải là giá trị được sao chép vào biến test.

Cách thích hợp để làm điều đó là bằng cách sử dụng một for bởi chỉ số:

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

trong trường hợp này bạn đang truy cập (và sửa đổi) các yếu tố cấu trúc thực tế và không phải là một bản sao của nó.

+0

Đáng ngạc nhiên điều này cũng có vẻ không hoạt động và dường như thay đổi giá trị của một bản sao. Xem câu trả lời của tôi dưới đây – reza23

+0

Xem nhận xét của tôi trong câu trả lời của bạn - kết quả thu được được mong đợi vì bạn vẫn đang xử lý các loại giá trị và không tham chiếu – Antonio

+2

@ reza23 Tác phẩm này. :) – nacho4d

0

Tôi đã thử câu trả lời của Antonio có vẻ khá logic nhưng tôi ngạc nhiên vì nó không hoạt động. Khám phá này hơn nữa tôi thử như sau:

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 
+6

Bạn quên rằng mỗi khi bạn vượt qua một loại giá trị xung quanh, bạn chuyển một bản sao của nó, chứ không phải là một tham chiếu. Vì vậy, kết quả bạn có được mong đợi. 'testing' được khởi tạo với một ** copy ** của' test1' và 'test2'. Một lần nữa, trong 'var test1b = testings [0]' bạn đang tạo một bản sao mới của 'testings [0]', bản thân nó là một bản sao của 'test1' – Antonio

2

Đây là câu trả lời rất khéo léo. Tôi nghĩ rằng, Bạn không nên làm như này:

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

Đối với Xcode 6.1, mảng khởi tạo sẽ

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

tôi đã kết thúc tái tạo một mảng mới của struct xem ví dụ dưới đây.

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

Tôi sẽ cập nhật câu trả lời của mình cho khả năng tương thích nhanh 3.

Khi bạn lập trình nhiều, bạn cần phải thay đổi một số giá trị của các đối tượng nằm trong bộ sưu tập. Trong ví dụ này, chúng ta có một mảng cấu trúc và đưa ra một điều kiện chúng ta cần phải thay đổi giá trị của một đối tượng cụ thể. Đây là một điều rất phổ biến trong bất kỳ ngày phát triển nào.

Thay vì sử dụng chỉ mục để xác định đối tượng nào phải được sửa đổi Tôi thích sử dụng điều kiện if, IMHO phổ biến hơn.

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) 

Lưu ý tất cả các cách cho phép, cách phát triển này an toàn hơn.

Các lớp là loại tham chiếu, không cần thiết phải tạo bản sao để thay đổi giá trị, giống như nó xảy ra với cấu trúc. Sử dụng cùng một ví dụ với các lớp học:

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) 
+0

Không làm bản đồ" bản đồ "của bạn? –

+0

@IanWarburton Xin lỗi, nhưng tôi không hiểu điều đó, ý bạn là gì "thuần khiết"? – LightMan

+0

Tôi cho rằng nó có nghĩa là phù hợp hơn với mô hình lập trình chức năng. –

0

Bạn có đủ câu trả lời hay. Tôi sẽ giải quyết các câu hỏi từ một góc độ chung chung hơn.

Như một ví dụ để hiểu rõ hơn về các loại giá trị và những gì nó có nghĩa là họ được sao chép:

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 
} 

Đó là vì mục được sao chép, khi nó đến, nó là bất biến - như là một tiện nghi.


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

anotherTest(item: item1) // 5 

Không đột biến xảy ra nên không có lỗi


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

Để đơn giản hóa làm việc với các loại giá trị trong mảng bạn có thể sử dụng phần mở rộng sau (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 
    } 
} 

Ví dụ sử dụng:

testings.modifyElement(atIndex: 0) { $0.value = 99 } 
testings.modifyForEach { $1.value *= 2 } 
testings.modifyForEach { $1.value = $0 } 
Các vấn đề liên quan