【问题标题】:Tuple-type in Swift generic constraintSwift 泛型约束中的元组类型
【发布时间】:2015-02-12 10:02:52
【问题描述】:

我正在尝试在 Swift 中编写一个通用函数,其约束条件是参数必须是成对的序列(我将把它变成字典)。这可能吗?我尝试了以下几种变体,但编译器不喜欢其中任何一种。

func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}

【问题讨论】:

    标签: swift generics tuples


    【解决方案1】:

    不是直接回答您的问题,但如果您想创建 字典,然后您可以将您的功能定义为扩展 方法到Dictionary 并使用Dictionary 定义的事实

    typealias Element = (Key, Value)
    

    那么你的方法声明可以是

    extension Dictionary {
        func foo<S : SequenceType where S.Generator.Element == Element>(xs : S) {
            //...
        }
    }
    

    要从元组创建字典,init 方法可能更合适,例如

    extension Dictionary {
    
        init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
    
            self.init()
            var gen = xs.generate()
            while let (key, value) : Element = gen.next() {
                self[key] = value
            }
        }
    }
    

    用法:

    let d = Dictionary(xs: [("a", 1), ("b", 2)])
    println(d) // [b: 2, a: 1]
    

    注意: 上面代码中通过generate()next() 的枚举 是一种解决方法,由于某种原因

    for (key, value) in xs { }
    

    不编译。比较Implementing Set.addSequence in Swift


    更新:Swift 2/Xcode 7开始,上述方法可以简化 到

    extension Dictionary {
    
        init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
            self.init()
            xs.forEach { (key, value) in
                self[key] = value
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      对我来说,这看起来像是一个编译器错误。

      这里的问题是:不能在泛型参数中直接使用元组类型

      正如@MartinR 在他的回答中所说,如果我们使用typealiased 元组类型,它就可以工作。但当然,我们不能在全局上下文中声明泛型 typealias

      例如,这个编译和工作:

      struct Foo<K,V> {
          typealias Element = (K,V)
          static func foo<S:SequenceType where S.Generator.Element == Element>(xs:S) {
              var gen = xs.generate()
              while let (k,v): Element = gen.next() {
                  println((k,v))
              }
          }
      }
      
      Foo.foo(["test":"foo", "bar": "baz"])
      

      还有一个想法是这样的:

      struct SequenceOfTuple<K,V>: SequenceType {
      
          typealias Element = (K,V)
      
          let _generate:() -> GeneratorOf<Element>
      
          init<S:SequenceType where S.Generator.Element == Element>(_ seq:S) {
              _generate = { GeneratorOf(seq.generate()) }
          }
          func generate() -> GeneratorOf<Element> {
              return _generate()
          }
      }
      
      func foo<K,V>(xs:SequenceOfTuple<K,V>) {
          for (k, v) in xs {
              println((k,v))
          }
      }
      
      foo(SequenceOfTuple(["test":"foo", "bar": "baz"]))
      

      在这种情况下,您必须将元组序列包装成SequenceOfTuple类型,然后将其传递给foo()

      嗯……

      【讨论】:

        【解决方案3】:

        您可以使用带有下标的结构并将结果存储在字典中:

        struct Matrix<K:Hashable, V> {
        
            var container:[K:[K:V]] = [:]
        
            subscript(x:K, y:K) -> V? {
                get {
                    return container[x]?[y]
                }
                set (value) {
                    if container[x] == nil {
                        container[x] = [:]
                    }
                    container[x]![y] = value
                }
            }
        }
        
        var matrix = Matrix<Int, String>()
        matrix[11,42] = "Hello World"
        
        println("(11,42): \(matrix[11,42])") // Optional("Hello World")
        println("(1,3): \(matrix[1,3])")     // nil
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多