我创建了一个名为ShoppingList的简单结构。

struct ShoppingList {

    var shoppingListId :NSNumber
    var title :String
    var groceryItems :[GroceryItem]

    init() {
        self.title = ""
        self.groceryItems = [GroceryItem]()
        self.shoppingListId = NSNumber(integer: 0)
    }

}

接下来,我创建了一个ShoppingList数组,如下所示:
 var shoppingLists = [ShoppingList]()

之后,我获取购物 list 等。现在,我遍历shoppingLists并更改标题,但它会更新title属性。
 for var shoppingList in shoppingLists {
  let items = getGroceryItemsByShoppingList(shoppingList)
    shoppingList.groceryItems = getGroceryItemsByShoppingList(shoppingList)
    shoppingList.title = "BLAH" // copied by value
    print("ShoppingList \(shoppingList.title) has \(shoppingList.groceryItems.count) items") // THIS PRINT BLAH
}

print("shoppingLists[0].groceryItems.count \(shoppingLists[0].groceryItems.count)") // THIS PRINTS THE ORIGINAL CONTENT

我相信,当我运行循环时,它是按值复制的,因此原始数组永远不会更改。如何使用For循环更改原始数组?

最佳答案

我将在这里使用两种方法。第一种方法是重新考虑ShoppingList是值类型还是引用类型。它具有标识符的事实向我表明,它实际上是引用类型。如果两个购物 list 的内容相同,是否应将其视为相同的 list ?我怀疑不是。具有相同标识符但内容不同的两个列表意味着什么?同样,如果那是非法的,则倾向于指出它是引用类型,因为它具有身份。

如果是引用类型,则将其设置为final class:

final class ShoppingList {}

最终类保留了结构的简单性,因为它们没有继承问题。但是它们提供了引用语义。有了这一更改,您的原始代码就可以使用。

解决此问题的另一种方法是更实用,其中一切都是有值(value)的。在这种情况下,您可以通过映射购物 list 的副本来实现:
shoppingLists = shoppingLists.map { list in
    var newList = list
    newList.groceryItems = getGroceryItemsByShoppingList(list)
    return newList
}

这将我们推向了一种更具功能性的方法,但是它使标识符变得笨拙。因此,如果您真的想这样做,我想摆脱标识符,甚至可以使购物 list 不可变。在这种情况下,任何两个相同的购物 list 都是相同的 list ,您可以使用更具功能性的样式进行编写。

但是我怀疑将ShoppingList用作引用类型是您更好的方法。

10-08 14:03