繁体   English   中英

如何在Swift 3中将通用序列参数约束到元组?

[英]How to constrain a generic sequence parameter to a tuple in Swift 3?

在Swift 2中,我能够编写一个可对任何序列进行操作的函数,例如(String, Int) 它看起来像这样:

func test<T: SequenceType where T.Generator.Element == (String, Int)>(input: T) {
    for (k, v) in input {
        print(k, "=", String(v))
    }
}

使用元组作为约束类型特别有用,因此它可以接受字典,例如[String:Int] ,因为它们的序列类型由元组组成。

在Swift 3中,我相信类似的功能将是:

func test<T: Sequence>(input: T) where T.Iterator.Element == (String, Int) {
    for (k, v) in input {
        print(k, "=", String(v))
    }
}

但是尝试传递[String:Int] ,例如: test(input: ["a": 1, "b": 2]) ,将导致错误:

无法推断通用参数“ T”

据我所知,Swift 3中的字典仍然使用(Key,Value)元组作为其迭代器类型,因此我认为这应该可行。 实际上,如果我不使用单一类型作为受约束的迭代器类型,例如where T.Iterator.Element == String ,那么我可以传入诸如[String]东西,并且它可以正常工作。

我缺少什么,或者这可能是Swift 3中的回归?

一个有趣的例子。

让我们检查关于符合SequenceDictionary的定义:

public func makeIterator() -> DictionaryIterator<Key, Value>

然后DictionaryIterator

public mutating func next() -> (key: Key, value: Value)?

因此,对于DictionaryT.Iterator.Element似乎是(key: Key, value: Value) ,而不是(Key, Value)

如果将函数重写为:

func test<T: Sequence>(input: T) where T.Iterator.Element == (key: String, value: Int) {
    for (k, v) in input {
        print(k, "=", String(v))
    }
}

这有效:

test(input: ["a": 1, "b": 2])

但这不起作用:

test(input: [("a", 1),("b",2)]) //->Generic parameter 'T' could not be inferred

我不确定这是预期的功能还是某种回归,还是仅仅是一个错误。

这是已知的错误( SR-992 ),在某些情况下,该错误会阻止编译器匹配相同类型但标签不同的元组。

一种可能允许您同时传递(String, Int)(key: String, value: Int)元组和[String : Int]字典的序列的可能解决方法是使test(input:)重载期望的函数以(key: String, value: Int)元素作为输入的序列。 然后,您可以使用懒惰求值的map来“擦除”元组标签,然后将该序列传递给test的原始实现。

// Overload to deal with [String : Int] inputs – workaround for a bug.
func test<T: Sequence>(input: T) where T.Iterator.Element == (key: String, value: Int) {
    // 'Erase' the tuple labels with a lazily evaluated map(_:)
    // and pass the sequence onto the original implementation of test(input:)
    test(input: AnySequence(input.lazy.map{($0.key, $0.value)}))
}

func test<T: Sequence>(input: T) where T.Iterator.Element == (String, Int) {
    for (k, v) in input {
        print(k, "=", v)
    }
}

let d = ["foo" : 5]
let a = [("key", 3)]

test(input: d) // prints: foo = 5
test(input: a) // prints: key = 3

也许不是最理想的解决方案-但据我所知,没有其他简单的解决方法可以解决此问题。 如果有人有更好的想法,肯定会感兴趣。

这不是快速的3。但是,它可能会有所帮助。

斯威夫特4

尚不允许参数化扩展。 因此,我们需要使用功能。

extension Result {
    func zip<A, B, C>(with other: Result<C, Failure>) -> Result<(A, B, C), Failure> where Success == (A, B) {
        return flatMap { (a, b) in
            Result<(A, B, C), Failure>.init(catching: {
                let c = try other.get()
                return (a, b, c)
            })
        }
    }
}

Result在哪里

public enum Result<Success, Failure: Error> {
    /// A success, storing a `Success` value.
    case success(Success)

    /// A failure, storing a `Failure` value.
    case failure(Failure)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM