2017-03-22 23 views
0

我想分解在Swift中使用泛型的方法。我的方法如下:帶泛型的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

也許嘗試重寫方法儘可能通用,只留下你的實際問題的位。現在我花了相當長的時間去了解泛型在哪裏可以用到。現在我的問題特別是你如何考慮處理'fooFrom'和'barFrom',因爲它們不是通用的。關於獲取泛型類型的名稱[this](http://stackoverflow.com/a/29879223/2442804)*可能*有幫助 – luk2302

+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) 
     } 
    } 
}