我在Swift中实现了一个使用Dictionary键的Set。我想实现一个addAll(序列)方法,该方法在Set中的Elements上采用任何序列类型,但是我得到一个没有意义的错误。这是我的代码
struct Set<Element: Hashable> {
var hash = [Element: Bool]()
init(elements: [Element] = []) {
for element in elements {
self.hash[element] = true
}
}
var array: [Element] {
return hash.keys.array
}
func contains(element: Element) -> Bool {
return hash[element] ?? false
}
mutating func add(element: Element) {
hash[element] = true
}
mutating func add(array: [Element]) {
for element in array {
hash[element] = true
}
}
mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
for element in sequence { // Error here: "Cannot convert the expression's type 'S' to type 'S'
hash[element] = true
}
}
mutating func remove(element: Element) {
hash[element] = nil
}
}
我在XCode 6.1和6.0.1中收到此错误。
我想遵循Array的extend方法的语义,但该类型签名甚至不能为我编译。
我做错了什么,还是应该提交雷达?
修改: 刚刚找到https://github.com/robrix/Set/blob/master/Set/Set.swift,它有这个实现:
public mutating func extend<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
// Note that this should just be for each in sequence; this is working around a compiler crasher.
for each in [Element](sequence) {
insert(each)
}
}
但是,这只是将sequence
转换为Array
,这种方式完全违背了SequenceType
的目的。
答案 0 :(得分:4)
更新:这已经在Swift 1.2(Xcode 6.3 beta 3)中得到修复,问题的原始代码编译没有错误。 (另外,定义
不再需要自定义集类型,因为Swift 1.2具有
内置Set
内置类型。)
旧答案:对我来说这看起来像个错误,但也许有人可以解释它。
可能的解决方法:
明确地将sequence
参数转换为SequenceOf<Element>
:
mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
for element in SequenceOf<Element>(sequence) {
hash[element] = true
}
}
(与https://stackoverflow.com/a/27181111/1187415中一样)替换for循环
通过使用序列生成器的next()
的while循环,并键入annotate
明确使用element : Element
:
mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
var gen = sequence.generate()
while let element : Element = gen.next() {
hash[element] = true
}
}
(来自"Creating a Set Type in Swift")使用map
:
mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
map(sequence) {
self.hash[$0] = true
}
}
答案 1 :(得分:3)
我能想到的最好的是马丁也制作的地图解决方案。有趣的是,手动扩展for循环:
mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
var generator = sequence.generate()
while let item = generator.next() {
self.hash[item] = true
}
}
在generator.next()
生成另一条错误消息:
Cannot convert the expression's type '()' to type 'Self.Element??'
使用reduce而不是map可能会更优化,因为它不构建要丢弃的数组:
mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) {
reduce(sequence, ()) {
self.hash[$1] = true
}
}