[英]swift type constraints on generic extensions
经过一些压力后,我创建了以下通用函数:
func removeDupes<T : Hashable > (inout inputCollection : [T] ) -> [T] {
var hashMap = [T : Bool]()
var output = 0
for thing in inputCollection {
if !hashMap[thing] {
hashMap[thing] = true
inputCollection[output++] = thing
}
}
while (inputCollection.count > output) {
inputCollection.removeLast()
}
return inputCollection
}
所以当你这样做时:
var names = ["Bob", "Carol", "Bob", "Bob", "Carol", "Ted", "Ted", "Alice", "Ted", "Alice"]
removeDupes(&names)
名称将包含:[“Bob”,“Carol”,“Ted”,“Alice”]
现在我想在Array上添加“removeDupes”作为扩展方法,我正在用语法进行挣扎,因为我必须将它限制为Hashable项的数组。
我希望我可以这样声明:
extension Array {
func removeDupes< T : Hashable> () -> [T] {
return removeDupes(&self)
}
}
但我得到错误:
数组不能转换为'@lvalue inout $ T5'
我怀疑答案是“你这个白痴,做这个......”还是“你做不到”
它会是哪个? :-D
Array
类声明如下:
public struct Array<Element>
由于雨燕2.0,您可以创建只为一般的情况下,扩展方法Element
参数符合协议:
extension Array where Element: Hashable {
@warn_unused_result
func removeDupes() -> [Element] {
var hashMap = [Element : Bool]()
var result = [Element]()
for thing in self {
if hashMap[thing] == nil {
hashMap[thing] = true
result.append(thing)
}
}
return result
}
}
注意扩展声明中的where
语句。 这样, removeDupes
方法仅针对Hashable
元素的数组声明:
let names = ["Bob", "Carol", "Bob", "Bob", "Carol", "Ted", "Ted", "Alice", "Ted", "Alice"]
let uniqueNames = names.removeDupes() // returns ["Bob", "Carol", "Ted", "Alice"]
您不能为比通用本身更具限制性的泛型定义模板化方法(仅适用于某些形式的泛型)。
此外,在扩展方法中定义T时,您定义的新T与Array中定义的T无关。 没有必要重新定义T,最终这就是您遇到的问题。 可以在泛型中定义新模板,但无法将这些模板与T和协议相关联。
您的原始函数是实现该函数的最佳方法,尽管返回没有重复项的数组副本而不是修改原始函数可能会更好。 这使得代码更加清晰,并且对于多线程更好(这对于执行这么多处理的方法可能很重要)。
Array定义为Array<T>
,这意味着Array可以保存任何类型T,并且T不一定符合Hashable
协议。 因此,您无法应用需要此约束的方法。 不幸的是,您也无法检查或向下转换此协议,因为Hashable
未使用@objc
属性声明 。
可以使用Dictionary删除重复项,但由于上面提到的相同原因,您不能使用T作为键。 但是,如果T唯一可表示为String,则应该可以:
extension Array {
func unique()->Array<T> {
var buffer = Dictionary<String,T>()
for it in self {
buffer["\(it)"] = it
}
return Array(buffer.values)
}
}
这是另一种方法,尽管正如drewag所说,这个方法会返回一个副本。 全局函数接受任何SequenceType
,但始终返回一个Array
因为SequenceType
是一种非常规类型,不允许附加值。
public func unique<H: Hashable, S: SequenceType where S.Generator.Element == H>(sequence: S) -> [H] {
var hashMap = [H: Bool]()
var result = [H]()
for elem in sequence {
let key = hashMap[elem]
if key == nil {
hashMap[elem] = true
result.append(elem)
}
}
return result
}
然后,在您的Array
扩展中:
public func unique<H: Hashable>() -> [H] {
return Yeah.unique(map({ $0 as H }))
}
我并不为这个解决方案而疯狂,因为数组遍历了两次:一次将其映射到Hashable,然后再次迭代它以删除重复项。 它的优点是通过委托全局函数,您可以非常快速地向任何采用SequenceType
类添加unique
方法。 我也不喜欢你被迫返回一个Array
的事实。 解决这个问题的方法可能是使用一个知道如何附加值的闭包来拥有全局unique
的重载。 值得深思。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.