Implementation of Set.addSequence in Swift

I implemented a set in Swift that uses dictionary keys. I want to implement the addAll (sequence) method, which accepts any type of sequence over elements in Set, but I get an error that does not make sense. Here is my code

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 type 'S' to type 'S' hash[element] = true } } mutating func remove(element: Element) { hash[element] = nil } } 

I get this error in Xcode 6.1 and 6.0.1.

I wanted to follow the semantics of the Array extension method, but a signature of this type does not even compile for me.

Am I doing something wrong, or do I need to file a radar?

edit : just found https://github.com/robrix/Set/blob/master/Set/Set.swift that has this implementation:

 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) } } 

However, this simply converts the sequence to Array , which generally hits the target of the SequenceType .

+5
source share
2 answers

Update: this was fixed in Swift 1.2 (Xcode 6.3 beta 3), the source code from the question compiles without errors. (In addition, the definition of a custom set type is no longer needed because Swift 1.2 has a built-in built-in Set type.)


Old answer: This seems like a mistake, but maybe someone can explain it.

Possible workarounds:

  • Convert the argument sequence in SequenceOf<Element> explicitly:

     mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) { for element in SequenceOf<Element>(sequence) { hash[element] = true } } 
  • (As in fooobar.com/questions/1206839 / ... ) Replace the for loop with the while loop using the next() generator of the sequence and the annotate type of the element explicitly with 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 } } 
  • (From "Creating a Set Type in Swift" ) Use map :

     mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) { map(sequence) { self.hash[$0] = true } } 
+4
source

The best I could come up with was a map solution, which Martin also created. Interestingly enough, manually extending the for loop like:

 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 } } 

Gives another error message in generator.next() :

 Cannot convert the expression type '()' to type 'Self.Element??' 

It might be somewhat more optimal to use a shorthand instead of a map, as this does not create an array for deletion:

 mutating func add<S : SequenceType where S.Generator.Element == Element>(sequence: S) { reduce(sequence, ()) { self.hash[$1] = true } } 
+3
source

Source: https://habr.com/ru/post/1206837/


All Articles