绕过Swift

时间:2016-06-07 16:29:38

标签: swift var let

这是一个简单的游乐场示例:

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中不推荐使用。相同的单行解决方法在那里工作。有没有更好的惯用方法来做到这一点?最初开始这个的是简单地将一些常见行为提取到协议扩展中,而不是继承树。感觉就像我为这个选择付了点钱。

1 个答案:

答案 0 :(得分:4)

,您的单线解决方案并不一定有效。您的协议不要求符合类型是引用类型(类)。如果结构符合您的协议,并且在数组中,var each = each将生成副本,修改副本将不会修改数组中的值。

您可以要求您的对象为类protocol Modifiable: class,在这种情况下,我相信将不再允许mutating(或者,至少您的代码将正常运行)。

但假设你想保留mutating,你可以这样做来修改元素:

for i in list.indices {
    list[i].modifyName()
}

当然,您的数组也必须是var,因为它也是value semantics的结构。