mes*_*ngr 7 protocols swift swift2
以下代码:
protocol SomeProtocol {
typealias SomeType = Int // used typealias-assignment
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) {
print(someVar)
}
}
Run Code Online (Sandbox Code Playgroud)
给出编译时错误:
使用未声明类型'SomeType'
例如typealias SomeType = Double,添加SomeClass可以解决错误.
问题是,虽然协议关联类型声明的typealias-assignment部分(可选btw)有什么意义?
在这种情况下的分配Int到typealias因为它可以让你的贴合型重载等于没有赋值:
// this declaration is equal since you HAVE TO provide the type for SomeType
protocol SomeProtocol {
typealias SomeType
func someFunc(someVar: SomeType)
}
Run Code Online (Sandbox Code Playgroud)
这样的赋值提供了一个默认类型,SomeType它被实现覆盖SomeClass,但它对协议扩展特别有用:
protocol Returnable {
typealias T = Int // T is by default of type Int
func returnValue(value: T) -> T
}
extension Returnable {
func returnValue(value: T) -> T {
return value
}
}
struct AStruct: Returnable {}
AStruct().returnValue(3) // default signature: Int -> Int
Run Code Online (Sandbox Code Playgroud)
只有通过符合协议而不指定类型,才能免费获得该功能T.如果要typealias T = String // or any other type在结构体中设置自己的类型.
有关提供的代码示例的一些其他说明
您解决了这个问题,因为您明确了该参数的类型.Swift还会推断您使用的类型:
class SomeClass: SomeProtocol {
func someFunc(someVar: Double) {
print(someVar)
}
}
Run Code Online (Sandbox Code Playgroud)
因此SomeType推断该协议Double.
另一个例子,你可以SomeType在类声明中看到它没有引用协议:
class SomeClass: SomeProtocol {
typealias Some = Int
func someFunc(someVar: Some) {
print(someVar)
}
}
// check the type of SomeType of the protocol
// dynamicType returns the current type and SomeType is a property of it
SomeClass().dynamicType.SomeType.self // Int.Type
// SomeType gets inferred form the function signature
Run Code Online (Sandbox Code Playgroud)
但是,如果你这样做:
protocol SomeProtocol {
typealias SomeType: SomeProtocol
func someFunc(someVar: SomeType)
}
Run Code Online (Sandbox Code Playgroud)
SomeType必须是SomeProtocol可以用于更明确的抽象和更多静态代码的类型,而这:
protocol SomeProtocol {
func someFunc(someVar: SomeProtocol)
}
Run Code Online (Sandbox Code Playgroud)
将动态调度.
协议中的" 关联类型 " 文档中有一些很好的信息.
它们在整个标准库中的使用非常丰富,例如参考SequenceType协议,它声明了一个typealiasfor Generator(并指定它符合GeneratorType).这允许协议声明引用该别名类型.
在你的情况下,你使用的地方typealias SomeType = Int,或许你的意思是" 我希望SomeType被约束为类似Integer的行为,因为我的协议方法将取决于那个约束 " - 在这种情况下,你可能想要typealias SomeType: IntegerType在你的协议中使用,然后在你的课堂上继续为那个符合的别名分配一个类型IntegerType.
UPDATE
在打开苹果公司的一个错误并对其进行了广泛的讨论后,我已经了解了基础问题的核心内容:
当符合协议时,您不能直接引用仅在该协议中声明的关联类型
(但请注意,在扩展协议时,相关类型可用,如您所料)
所以在你的初始代码示例中:
protocol SomeProtocol {
typealias SomeType = Int
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) { // use of undeclared type "SomeType"
print(someVar)
}
}
Run Code Online (Sandbox Code Playgroud)
...错误重新:"使用未声明的类型"是正确的,您的类SomeClass没有声明类型SomeType
但是,扩展可以SomeProtocol访问关联类型,并且在提供实现时可以引用它:
(请注意,这需要使用where子句来定义关联类型的要求)
protocol SomeProtocol {
typealias SomeType = Int
func someFunc(someVar: SomeType)
}
extension SomeProtocol where SomeType == Int {
func someFunc(someVar: SomeType) {
print("1 + \(someVar) = \(1 + someVar)")
}
}
class SomeClass: SomeProtocol {}
SomeClass().someFunc(3) // => "1 + 3 = 4"
Run Code Online (Sandbox Code Playgroud)