我一直在努力为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 :(得分:3)
人们使用向下铸造的原因......按照以下方式:
unsafeBitCast(self, [X].self) // where self is the array and `X` is the type of the passed in value
...是因为尝试以任何方式限制Array
的{{1}}类型无异于:
Element
实现类似功能(不使用全局函数)的一种方法是将比较推迟到调用时间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]
答案 1 :(得分:0)
我认为你无法达到你想要的效果。在与斯威夫特玩了一段时间后,我得出的结论是,在写这篇文章的时候,#34;自然&#34;在Swift中做事的方法是结合扩展和全局功能。您会注意到这正是Swift开箱即用的方式。例如,Array
缺少contains
方法,但有一个全局contains
函数适用于任何SequenceType
。为什么这样做?由于Swift类型系统的局限性。 Array<T>
可以包含任何类型,但contains
的正确实施需要Equatable
。将T
约束为Equatable
的唯一方法是使用全局函数,这就是Swift所做的。此外,如果您想在序列上编写真正的泛型函数,而不仅仅是Array<T>
,那么您应该编写以SequenceType
作为参数的全局函数,特别是因为它是无法在SequenceType
上编写扩展方法,因此其功能必须是全局的。 (虽然有很多方法可以解决这个问题,例如,通过创建扩展SequenceType
的协议,但是您必须声明支持该扩展协议的所有类型。不是我的第一选择。)
所以,我不会做你想做的事情。在斯威夫特,我感觉不自然,即使斯威夫特的做事方式对于来自C#或Java的人来说感觉不自然。然而,如果被迫,我认为Milos已经提出了一个很好的解决方案,你将会得到。
希望Swift的未来迭代将允许我们使用泛型类型约束创建扩展方法。在那之前,我将使用SequenceType
而非[T]
以上的全局函数。