协议关联类型类型别名分配编译错误
protocol associated type typealias assignment compile error
以下代码:
protocol SomeProtocol {
typealias SomeType = Int // used typealias-assignment
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) {
print(someVar)
}
}
给出编译时错误:
Use of undeclared type 'SomeType'
将 typealias SomeType = Double
添加到 SomeClass
可以解决错误。
问题是,协议关联类型声明的 typealias-assignment 部分(顺便说一下,这是可选的)有什么意义?
great article 确实为您提供了问题的答案。我建议大家阅读它以了解类型别名和使用它时出现的一些更高级的东西。
网站引用:
Conceptually, there is no generic protocols in Swift. But by using
typealias we can declare a required alias for another type.
在这种情况下,Int
到 typealias
的赋值等于没有赋值,因为它被您的符合类型覆盖:
// this declaration is equal since you HAVE TO provide the type for SomeType
protocol SomeProtocol {
typealias SomeType
func someFunc(someVar: SomeType)
}
这样的分配为 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
不指定T
的类型,只要符合协议即可免费获取功能。如果您想设置自己的类型,请在结构体中写入 typealias T = String // or any other type
。
关于提供的代码示例的一些附加说明
你解决了这个问题,因为你明确了参数的类型。 Swift 还可以推断您使用的类型:
class SomeClass: SomeProtocol {
func someFunc(someVar: Double) {
print(someVar)
}
}
所以协议的SomeType
被推断为Double
.
另一个示例,您可以看到 class 声明中的 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
但是,如果您这样做:
protocol SomeProtocol {
typealias SomeType: SomeProtocol
func someFunc(someVar: SomeType)
}
SomeType
必须是 SomeProtocol
类型,可用于更明确的抽象和更静态的代码,而此:
protocol SomeProtocol {
func someFunc(someVar: SomeProtocol)
}
将被动态调度。
协议中关于“associated types”的文档中有一些重要信息。
它们在整个标准库中的使用非常丰富,例如参考 SequenceType 协议,它为 Generator
声明了 typealias
(并指定它符合 GeneratorType
).这允许协议声明引用该别名类型。
在你的情况下,你使用 typealias SomeType = Int
,也许你的意思是“我希望 SomeType 被限制为类似 Integer 的行为,因为我的协议方法将取决于该限制" - 在这种情况下,您可能希望在协议中使用 typealias SomeType: IntegerType
,然后在 class 中继续为符合 IntegerType
的别名分配类型.
更新
在与 Apple 就此打开一个错误并围绕它进行了广泛讨论后,我开始了解基本问题的核心是什么:
当遵循协议时,您不能直接引用仅在该协议中声明的关联类型
(但是请注意,当 扩展 协议时,关联类型可用,如您所料)
因此在您的初始代码示例中:
protocol SomeProtocol {
typealias SomeType = Int
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) { // use of undeclared type "SomeType"
print(someVar)
}
}
...错误回复:"use of undeclared type" 是正确的,您的 class 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"
以下代码:
protocol SomeProtocol {
typealias SomeType = Int // used typealias-assignment
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) {
print(someVar)
}
}
给出编译时错误:
Use of undeclared type 'SomeType'
将 typealias SomeType = Double
添加到 SomeClass
可以解决错误。
问题是,协议关联类型声明的 typealias-assignment 部分(顺便说一下,这是可选的)有什么意义?
great article 确实为您提供了问题的答案。我建议大家阅读它以了解类型别名和使用它时出现的一些更高级的东西。
网站引用:
Conceptually, there is no generic protocols in Swift. But by using typealias we can declare a required alias for another type.
在这种情况下,Int
到 typealias
的赋值等于没有赋值,因为它被您的符合类型覆盖:
// this declaration is equal since you HAVE TO provide the type for SomeType
protocol SomeProtocol {
typealias SomeType
func someFunc(someVar: SomeType)
}
这样的分配为 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
不指定T
的类型,只要符合协议即可免费获取功能。如果您想设置自己的类型,请在结构体中写入 typealias T = String // or any other type
。
关于提供的代码示例的一些附加说明
你解决了这个问题,因为你明确了参数的类型。 Swift 还可以推断您使用的类型:
class SomeClass: SomeProtocol {
func someFunc(someVar: Double) {
print(someVar)
}
}
所以协议的SomeType
被推断为Double
.
另一个示例,您可以看到 class 声明中的 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
但是,如果您这样做:
protocol SomeProtocol {
typealias SomeType: SomeProtocol
func someFunc(someVar: SomeType)
}
SomeType
必须是 SomeProtocol
类型,可用于更明确的抽象和更静态的代码,而此:
protocol SomeProtocol {
func someFunc(someVar: SomeProtocol)
}
将被动态调度。
协议中关于“associated types”的文档中有一些重要信息。
它们在整个标准库中的使用非常丰富,例如参考 SequenceType 协议,它为 Generator
声明了 typealias
(并指定它符合 GeneratorType
).这允许协议声明引用该别名类型。
在你的情况下,你使用 typealias SomeType = Int
,也许你的意思是“我希望 SomeType 被限制为类似 Integer 的行为,因为我的协议方法将取决于该限制" - 在这种情况下,您可能希望在协议中使用 typealias SomeType: IntegerType
,然后在 class 中继续为符合 IntegerType
的别名分配类型.
更新
在与 Apple 就此打开一个错误并围绕它进行了广泛讨论后,我开始了解基本问题的核心是什么:
当遵循协议时,您不能直接引用仅在该协议中声明的关联类型
(但是请注意,当 扩展 协议时,关联类型可用,如您所料)
因此在您的初始代码示例中:
protocol SomeProtocol {
typealias SomeType = Int
func someFunc(someVar: SomeType)
}
class SomeClass: SomeProtocol {
func someFunc(someVar: SomeType) { // use of undeclared type "SomeType"
print(someVar)
}
}
...错误回复:"use of undeclared type" 是正确的,您的 class 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"