这是一个简单的游乐场示例:
class Foobar {
var name = ""
init(name:String) {
self.name = name
}
func modifyName(modification:String) {
self.name += modification
}
}
let list = [Foobar(name:"I"), Foobar(name:"Me"), Foobar(name:"Myself")]
for each in list {
each.modifyName(" rules")
}
具有name
变量的类,以及可以修改该变量的单个函数。列出它们,现在使用for in
来执行修改功能。
BUT。如果我将modifyName变量重构为协议扩展:
class Foobar {
var name = ""
init(name:String) {
self.name = name
}
}
protocol Modifiable {
var name:String { get set }
}
extension Modifiable {
mutating func modifyName(modification:String) {
self.name += modification
}
}
extension Foobar:Modifiable { }
然后for in
将不再有效,因为将Modifiable
注释为modifyName
需要mutating
扩展名。发出的错误是error: cannot use mutating member on immutable value: 'each' is a 'let' constant
。有一个简单的解决方法,但感觉我在滥用某些东西:
for each in list {
var each = each
each.modifyName(" rules")
}
我的函数有一个带有注释标记的参数,我遇到了同样的问题。过去,您可以在arg列表中使用var
标记这些参数,但在最新版本的swift中不推荐使用。相同的单行解决方法在那里工作。有没有更好的惯用方法来做到这一点?最初开始这个的是简单地将一些常见行为提取到协议扩展中,而不是继承树。感觉就像我为这个选择付了点钱。
答案 0 :(得分:4)
否,您的单线解决方案并不一定有效。您的协议不要求符合类型是引用类型(类)。如果结构符合您的协议,并且在数组中,var each = each
将生成副本,修改副本将不会修改数组中的值。
您可以要求您的对象为类protocol Modifiable: class
,在这种情况下,我相信将不再允许mutating
(或者,至少您的代码将正常运行)。
但假设你想保留mutating
,你可以这样做来修改元素:
for i in list.indices {
list[i].modifyName()
}
当然,您的数组也必须是var
,因为它也是value semantics的结构。