2014-10-02 26 views
2

我一直在努力實現一個Swift數組的擴展以按值刪除元素。有人提出使用向下澆注的解決方案,我試圖避免由於與動態類型檢查相關的成本。你能指出如何獲得下面的代碼來編譯。Swift Array擴展刪除元素的值沒有轉換

感謝,


protocol Removable: SequenceType { 
    typealias Element 
    mutating func remove(v: Element) -> Bool 
} 

func removeElementByValue<T: Equatable>(inout array: [T], valueToRemove: T) -> Bool { 
    for (index, value) in enumerate(array) { 
     if value == valueToRemove { 
      array.removeAtIndex(index) 
      return true 
     } 
    } 
    return false 
} 

extension Array: Removable { 
    mutating func remove(v: T) -> Bool { 
     return removeElementByValue(&self, v) // compile error here 
    } 

// tried also with: 
// mutating func remove<E:Equatable where E == T>(v: T) -> Bool 
} 
+0

感謝@milos您的迴應。我真正希望達到的目的是爲了編譯。我可以在擴展中移動全局函數,在平等檢查時應用投射,並且可以工作。這裏是關心的問題,假定協議和函數在給定的情況下如何獲得以上編譯。因此,我的結論是,除了我缺乏協調跨協議的知識之外,泛型和擴展可能是語言需要更多地指定where子句。 – Atila 2014-10-04 18:51:40

回答

3

人使用下鑄造的原因...線沿線的:

unsafeBitCast(self, [X].self) // where self is the array and `X` is the type of the passed in value 

...是因爲試圖限制ArrayElement以任何方式鍵入無異於:

extension Array<T: Equatable> {} // --> Compiler error: Extension of generic type 'Array' cannot add requirements 

,以實現類似的功能性(不訴諸全局函數)的方法是推遲比較到調用代碼,通過該時間Element的類型被解析和已知可能是Equatable與否:

var array = [1,2,3,4,5] 
let filtered = array.filterOut { $0 == 3 } 
filtered // --> [1,2,4,5] 

...或者,更接近你想達到什麼目的:

let didRemove = array.remove { $0 == 3 } 
didRemove // --> true 
array // --> [1,2,4,5] 

...這可以實現,例如,如下:

extension Array { 

    func filterOut(predicate: T -> Bool) -> [T] { 
     return self.filter { !predicate($0) } 
    } 

    mutating func remove(predicate: T -> Bool) -> Bool { 
     let count = self.count 
     self = self.filterOut(predicate) 
     return count != self.count 
    } 
} 
0

我不認爲你可以達到你想要的。在Swift中玩了一段時間之後,我得出結論,在撰寫本文時,在Swift中做事的「自然」方式是將擴展和全局函數結合在一起。你會注意到,這正是Swift開箱即用的原因。例如,Array缺少contains方法,但有一個全球contains函數可與任何SequenceType一起使用。爲什麼這樣做?由於Swift類型系統的侷限性。 Array<T>可以包含任何類型,但contains的正確實施需要Equatable。將T約束爲Equatable的唯一方法是使用全局函數,這就是Swift所做的。另外,如果要在序列上編寫真正的通用函數,而不是僅編寫Array<T>,則應該編寫以SequenceType作爲參數的全局函數,特別是因爲無法在SequenceType上編寫擴展方法,所以其函數必須是全球性的。 (雖然有辦法解決這個問題,例如通過創建一個延伸到SequenceType的協議,但是你必須聲明支持該擴展協議的所有類型,而不是我的第一選擇。)

所以,不要做你想做的事情。 Swift對我來說感覺不太自然,即使Swift對某些來自C#或Java的人的做法感覺不自然。但是,如果受到壓力,我認爲米洛斯已經提出了一個好的解決方案,因爲你會得到。

希望未來的Swift迭代將允許我們創建具有泛型類型約束的擴展方法。直到那一天,我將使用全局函數而不是SequenceType而不是[T]