Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
704 views
in Technique[技术] by (71.8m points)

generics - Implementing Set.addSequence in Swift

I've implemented a Set in Swift that uses Dictionary keys. I want to implement an addAll(sequence) method that takes any sequence type over the Elements in the Set, but I'm getting an error that doesn't make sense. Here's 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's type 'S' to type 'S'
            hash[element] = true
        }
    }

    mutating func remove(element: Element) {
        hash[element] = nil
    }
}

I'm getting this error in XCode 6.1 and 6.0.1.

I wanted to follow the semantics of Array's extend method, but that type signature doesn't even compile for me.

Am I doing something wrong, or should I file a Radar?

edit: just found https://github.com/robrix/Set/blob/master/Set/Set.swift, which 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, that just converts sequence into an Array, which kind of defeats the purpose of SequenceType altogether.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Update: This has been fixed in Swift 1.2 (Xcode 6.3 beta 3), the original code from the question compiles without errors. (Also, defining a custom set type is not necessary anymore because Swift 1.2 has a native Set type built-in.)


Old answer: It looks like a bug to me, but perhaps someone can explain it.

Possible workarounds:

  • Convert the sequence argument to 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 https://stackoverflow.com/a/27181111/1187415) Replace the for-loop by a while-loop using next() of the sequence generator, and type annotate 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
        }
    }
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...