[英]How to constrain a Swift generic type parameter to be any protocol and another parameter to conform to it?
[英]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中的回歸?
一個有趣的例子。
讓我們檢查關於符合Sequence
的Dictionary
的定義:
public func makeIterator() -> DictionaryIterator<Key, Value>
然后DictionaryIterator
:
public mutating func next() -> (key: Key, value: Value)?
因此,對於Dictionary
, T.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。但是,它可能會有所幫助。
尚不允許參數化擴展。 因此,我們需要使用功能。
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.