2014-10-02 63 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]