簡體   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