为什么这个Swift结构需要“变异”?

时间:2019-03-31 14:30:19

标签: swift immutability

我在Swift中缺少关于可变性概念的东西。我通常使用对象而不是结构来获得可观察性,因此值语义对我来说仍然是新的。

struct Game {
  var map: [[Int]]

所以在这里,我宣布map为可变的。那么为什么要使用这种方法...

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

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

还有其他方法可以执行此操作吗? mutating的常用用法是否表示我应该避免的性能/内存问题?

更新:我对结构的内部状态“泄漏”到周围代码的方式感到不安;如果在结构内部声明成员var,则即使您从未更改,它也必须在结构外部。这违反了我能想到的每个封装概念。因此,我将struct更改为class,删除了所有mutating并完成了操作。我知道了,但是我不确定我是否完全理解实现。在这个Swift-noob看来,mutating是编译器可以在不通知我的情况下确定的-成员是否声明为var?func实际上会对其进行突变吗?等

2 个答案:

答案 0 :(得分:2)

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

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

由于您的财产不是私人财产,您仍然可以这样做

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

答案 1 :(得分:0)

在Swift中,结构具有值语义,即,即使出于性能原因将它们StringArray之类的某些对象实现为引用,也可以将它们视为值。如果您不是该结构的唯一所有者,则在对这样的结构进行突变时,编译器实际上可能必须进行复制。这就是所谓的写时复制,这是变异指示的可能的性能问题。