2

根据文档

通过将 inout 关键字放在其参数定义的开头来编写一个 in-out 参数。in-out 参数有一个值,该值被传入函数,被函数修改,并被传回函数以替换原始值。

但是如果根本没有改变,如何不复制结果

我有一个数据库解析器,它仅在值更改时分配attr,但是,随着 inout 的行为,attr传入的总是设置(标记我的数据库对象脏和更改:/)

func importStringAttribute(_ json: JSON, _ key: String, _ attr: inout String?) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != attr {
        attr = v
    }
}

// the myDBObject.someAttr is always set 
importStringAttribute(json, "someAttr", &myDBObject.someAttr)

有没有修改的方法,所以只有在传入的属性真正改变时才设置值?

4

2 回答 2

1

这是如何inout工作的。你无法改变这一点。inout字面意思是“在开始时将值复制到函数中,并在结束时将值从函数中复制出来”。它不做任何分析来决定该值是否在运行时被触及。

一种解决方案是检查观察者中的琐碎集合,例如:

var someAttr: String? {
    didSet {
        guard someAttr != oldValue else { return }
        ...
    }
}

作为另一种方法,我建议使用键路径。假设数据库对象是引用类型(类),我相信下面会做你想要的:

func importStringAttribute(_ json: JSON, _ key: String, db: Database,
                           attr: ReferenceWritableKeyPath<Database, String?>) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != db[keyPath: attr] {
        db[keyPath: attr] = v
    }
}

调用稍长一些,因为您需要传递数据库本身:

importStringAttribute(json, "someAttr", db: myDBObject, attr: \.someAttr)

通过将方法附加到数据库可以使这更漂亮一些(尽管您仍然必须传递数据库,就像 self 一样):

extension Database {
    func importStringAttribute(_ json: JSON, _ key: String,
                               _ attr: ReferenceWritableKeyPath<Database, String?>) {
        if !json[key].exists() {
            return
        }
        if let v = json[key].string, v != self[keyPath: attr] {
            self[keyPath: attr] = v
        }
    }

}

myDBObject.importStringAttribute(json, "someAttr", \.someAttr)

对于您关于使这个泛型超过类型的问题,这非常简单(我刚刚添加<Obj: AnyObject>并将对“db”的引用更改为“obj”):

func importStringAttribute<Obj: AnyObject>(_ json: JSON, _ key: String, obj: Obj,
                           attr: ReferenceWritableKeyPath<Obj, String?>) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != obj[keyPath: attr] {
        obj[keyPath: attr] = v
    }
}
于 2020-03-27T13:50:00.143 回答
1

一种解决方案是将集合移动到一个块中

importStringAttribute(json, "someAttr", &myDBObject.someAttr)

importStringAttribute(json, "someAttr", myDBObject.someAttr) { myDBObject.someAttr = $0}

代码

func importStringAttribute(_ json: JSON, _ key: String, _ attr: String?, set:(_ value: String?)->()) {
    if !json[key].exists() {
        return
    }
    if let v = json[key].string, v != attr {
        set(v)
    }
}
于 2020-03-27T14:17:04.120 回答