![](/img/trans.png)
[英]Access associated type of a custom protocol in a where clause on generic types in Swift
[英]Associated type constraints with generic types and protocols enables bypass of the WHERE clause
为了完全理解问题,我在代码中评论了我的想法。 为了便于查看,您可以将粘贴复制到 SWIFT 操场上。 不确定这是错误还是对类型推断的根本误解。 我能够通过“欺骗”类型推断来绕过 WHERE 子句,让我发送不同的类型。
import Foundation
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
struct Stack<U>: Container {
var items = [U]()
mutating func push(_ item: U) {
items.append(item)
}
mutating func pop() -> U {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(_ item: U) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> U {
return items[i]
}
}
struct Devin {} /// This is to describe a custom type.
extension Devin: Container {
//typealias Item = String
/// NOTE: Eventhough the typealias is omitted, the type is inferred as String due to the pattern defined here.
mutating func append(_ item: String) {
/// do nothing
}
var count: Int {
/// do nothing
return 0
}
subscript(i: Int) -> String {
/// do nothing
return "0"
}
}
/// and here comes the confusing part.......
// Using a PROTOCOL in its ASSOCIATED TYPE'S constraints
protocol SuffixableContainer: Container {
/// Here we are saying SUFFIX like the ITEM constraint before is a type that conforms to this protocol being defined and the actual constraint is the where clause.
associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
/// Suffix has two constraints: It must conform to the SuffixableContainer protocol (the protocol currently being defined)
/// and its Item type must be the same as the container’s Item type. ( what does it look like when they arent the same? )
/// to understand whats happening here you have to see how its being used.
///
/// here is where its getting used and this is the important piece
func suffix(_ size: Int) -> Suffix
}
extension Stack: SuffixableContainer {
/// when conforming
func suffix(_ size: Int) -> Stack {
var result = Stack()
for index in (count-size)..<count {
result.append(self[index])
}
return result
}
// Inferred that Suffix is Stack.
}
/// in the commented out code below:
/// Eventhough, returning a stack in the generic form passed, returning one of a different type than the STRING that was inferred will throw an error.
/// Here we can return an instance of Devin and be fine but when we return an instance of a Stack that is a INT type it errors.
//extension Devin: SuffixableContainer {
// func suffix(_ size: Int) -> Stack<Int> {
// return Stack<Int>()
// }
//}
/// Error: note: requirement specified as 'Self.Item' == 'Self.Suffix.Item' [with Self = Devin]
/// This is the behavior you would expect
/// But here is a different story
/// Return ( Stack = just fine | Devin = just fine | Stack<Devin> = no go my friend )
extension Devin: SuffixableContainer {
func suffix(_ size: Int) -> Devin {
print(size)
return Devin()
}
}
print(Devin.Suffix.self)
print(Devin.Item.self)
if Devin.Item.self == Devin.Suffix.self {
print("It Worked")
} else {
print("They arent the same")
/// For those who can guess it will print that they aren't the same which violates the where clause
}
let store = Devin.suffix(Devin())
/// Not sure I understand why this works
/// now here is where I can really see the issue.
/// After printing the two types Devin does not equal String &
/// Devin and String are not the same types and the where clause didnt throw any error.
/// And for whatever reason I can pass the Devin object
where
子句不限制Devin.Suffix
与Devin.Item
相同,它限制Devin.Suffix.Item
与Devin.Item
相同。
保持其他一切不变,以下代码打印It Worked
。
print(Devin.Suffix.Item.self)
print(Devin.Item.self)
if Devin.Item.self == Devin.Suffix.Item.self {
print("It Worked")
} else {
print("They aren't the same")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.