为什么这个 Swift 结构需要 "mutating"?

Why does this Swift struct require "mutating"?

我在 Swift 中遗漏了一些关于可变性概念的内容。我通常使用对象而不是结构来获得可观察性,因此值语义对我来说仍然是新的。

struct Game {
  var map: [[Int]]

所以我在这里声明 map 是可变的。那么为什么在这样的方法中...

  mutating func createPlayer() {
    // emptyLocation -> (Int, Int)
    let (X,Y) = emptyLocation()
    map[X][Y] = .player
  }

...我必须使用变异吗?是的,该函数正在发生变化,但原始结构是这样声明的。似乎实际上每个 func 都会 mutating 实际上,这似乎违背了标记的目的。

有没有其他方法可以做到这一点? mutating 的常见用法是否表明我应该避免 performance/memory 问题?

更新: 我对结构 "leaked out" 的内部状态到周围代码的方式感到相当不安;如果你在结构内部声明一个成员 var 那么它也必须在外部,即使你从未改变过。这违反了我能想到的每一个封装概念。所以我将 struct 更改为 class,删除了所有 mutating,并完成了它。我明白了,但我不确定我是否完全理解实现。对于这个 Swift-noob 来说,mutating 似乎是编译器可以在我不告诉它的情况下确定的东西 - 成员声明为 var 吗?函数是否真的改变了它?等等

是的,structenum 的默认行为是实例方法不能修改 属性,因为它们是值类型。所以你需要使用 mutating 来覆盖这个行为。

您定义 属性 var 或 let 的方式仍然与是否可以从可变实例方法或直接更改它有关。

由于您的属性不是私人的,您仍然可以

var g = Game(map: [[1]])
g.map.append([2])

在 Swift 中,结构具有值语义,即它们的行为就好像它们是值,即使其中一些像 StringArray 出于性能原因被实现为引用。当您改变这样的结构时,如果您不是该结构的唯一所有者,编译器实际上可能必须制作一个副本;这被称为写入时复制,这是变异指示的可能的性能问题。