我知道这个模式有一个名字,不记得它是什么。基本上有一个方法返回一个瞬态/蹦床的东西,通过API操纵原始。 Mediator
可能吗?
我试图在Swift playground中的一个简单示例中实现它:
struct Count {
var value = 0
func adjuster() -> Adjuster {
return Adjuster(target:self)
}
}
struct Adjuster {
var target:Count
func increment(delta:Int) {
self.target.value = self.target.value + delta
}
}
var f = Count()
f.adjuster().increment(13)
首先,这有助于告诉我increment
方法需要标记为mutating
。我有点不清楚为什么。如果它改变它自己的var,我会明白为什么,而不是另一个的var。那好吧。所以我让IDE为我插入变异。但后来它与最后一行“测试”案件有关。它产生了这个错误:
...: error: cannot use mutating member on immutable value: function call returns immutable value
f.adjuster().increment(13)
~~^~~~~~~~~~
我并不完全了解这里的问题。它也不能为我“修复它”。那么这里发生了什么?如何实现这种模式?
答案 0 :(得分:3)
如果您的方法改变了其属性(-ies),则使用shift up
(与struct
不同),必须使用class
关键字进行标记。
在你的情况下它应该是:
mutating
结构和枚举是值类型。默认情况下,无法在其实例方法中修改值类型的属性。
但是,如果需要在特定方法中修改结构或枚举的属性,则可以选择改变该方法的行为。然后,该方法可以从方法中改变(即更改)其属性,并且当方法结束时,它所做的任何更改都将写回原始结构。
“如果它改变它自己的var,我会明白为什么,而不是另一个变种。”
为什么它仍然抱怨“变异”的原因,虽然它不是它自己的属性,但另一个属性,是两者都是价值类型。这意味着如果您在mutating func increment(delta:Int) { ... }
内更改Count
的属性,您仍然可以修改Adjuster
(它是值类型,而不是对象)。因此需要Count
。
我没有看到mutating
的实现,所以我不能确切地说出最后一条错误消息的原因,但我猜它有相同的根本原因,也就是说,值类型不是正确的适应设计模式。所以,你可能会更好地使用类,而不是结构。
答案 1 :(得分:2)
您必须将struct
更改为class
才能使其正常运行。
因为struct
是按值复制的,所以在此行中
return Adjuster(target:self)
调整器将获得目标的新副本并保存。在increment
方法中,您尝试修改self.target.value
,这意味着您正在修改self.target
,因此基本上修改了self
。
但还有更多问题,因为struct
是值类型,所以
var count: Count // count.value = 0
var adjuster = count.adjuster()
adjuster.increment(1)
您希望count.value
为1,但事实并非如此。 count.value
将保持为0,adjuster.target.count
将为1.您现在的代码现在非常混乱,您想知道错误是什么。
真正的问题是你正在用OOP实现设计模式和原始的纯函数模式,所以它们不能很好地协同工作。
如果您想要遵循一些最佳做法指南并且更喜欢struct
而不是class
,那么您也可以使用功能方法。即没有突变
struct Count {
let value = 0
}
func increment(count:Count, delta:Int) -> Count {
return Count(value:count.value + delta)
}