带有泛型的Swift重构:我如何从泛型类型中暗示运行时值?

时间:2017-03-22 11:18:48

标签: swift generics swift3 functional-programming refactoring

我正在尝试使用Swift中的泛型分解方法。我的方法如下:

func searchFoo(searchText: String?, completion: @escaping ([Foo]?, Error?) -> ()) {
    let index = "foo" // <- How can I assign this from a generic type?
    searchClient.search(index, searchText) { (json, error) in
        if let json = json {
            completion(self.fooFrom(json: json), nil)
        } else if let error = error {
            completion(nil, error)
        } else {
            completion([], nil)
        }
    }
}

func searchBar(searchText: String?, completion: @escaping ([Bar]?, Error?) -> ()) {
    let index = "bar" // <- How can I assign this from a generic type?
    searchClient.search(index, searchText) { (json, error) in
        if let json = json {
            completion(self.barFrom(json: json), nil)
        } else if let error = error {
            completion(nil, error)
        } else {
            completion([], nil)
        }
    }
}

这两个函数看起来像是一个很好的泛型用例,但我无法弄清楚如何打开泛型类型来获取2个必需的字符串。

当然,我可以将索引名称放在函数签名中,但我觉得它是多余的,因为索引名称是由实际使用的泛型类型暗示的,它可能是bug的来源。

我觉得我错过了一些东西,因为我可能还没有认为Swift方式,所以欢迎任何帮助以获得对此代码的良好重构。

1 个答案:

答案 0 :(得分:2)

您可以通过创建协议来实现此目的:

protocol Baz {
    static var index: String { get }
    static func loadFromJSON(json: JSONObject) -> [Self]
}

然后扩展FooBar以符合此协议。最后,为搜索功能添加通用约束:

func search<T: Baz>(searchText: String?, completion: @escaping ([T]?, Error?) -> ()) {
    searchClient.search(T.index, searchText) { (json, error) in
        guard error == nil else { completion(nil, error!) }

        if let json = json {
            completion(Baz.loadFromJSON(json: json), nil)
        } else {
            completion([], nil)
        }
    }
}