Swift Array扩展,用于按值删除元素而不进行强制转换

时间:2014-10-02 10:46:01

标签: 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 
}

2 个答案:

答案 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]以上的全局函数。