Swift 2.0:创建符合通用协议的对象集合类型
Swift 2.0: Creating a Collection Type of Objects that conform to a Generic Protocol
例如:
protocol SomeProtocol {
typealias T
func doSomething(something: T)
}
let a = Array<SomeProtocol>()
我想要一个数组,它是一个符合 SomeProtocol
的对象数组。这在理论上似乎很好,但我收到以下错误消息:
Cannot be used as a generic constraint because it contains assosciated
type requirements.
我想这是有道理的,毕竟 Array 也是一个通用结构,所以编译器将无法弄清楚给定 SomeProtocol
和 [=14= 两者的实际类型是什么] 是通用的。
所以我的问题是 - 我觉得我应该能够拥有一组符合 SomeProtocol
的对象 - 目前在 Swift 2.0 中这可能吗?我是不是以完全错误的方式思考这个问题?
不,不可能像现在这样 Swift 2. 泛型类型只有在指定泛型参数后才能使用。对于泛型类、结构体和枚举,它们的泛型参数可以在使用时同时指定。例如一个数组可以这样使用:
let anArray: [String]
此处将Array
的泛型参数指定为String
,当Array
作为变量类型时
但是,泛型协议(具有关联类型的协议,命名为typealias)只有在具体类型符合它时才能指定其关联类型。当您使用泛型协议作为变量类型时,您无法提供关联类型,例如泛型 类、结构或枚举。
此错误消息的原因是如果您的 Array
声明有效,则会出现以下问题:
protocol SomeProtocol {
typealias T
func doSomething(something: T)
}
// has already some values
let a: Array<SomeProtocol> = [...]
// what type should be passed as parameter?
// the type of T in SomeProtocol is not defined
a[0].doSomething(...)
作为解决方法,您可以为任何类型的 SomeProtocol
创建一个通用包装器结构,这样您就可以指定 T
的类型(就像在 Swift 标准库 AnyGenerator、AnySequence 中一样, ...).
struct AnySomeProtocol<T>: SomeProtocol {
let _doSomething: T -> ()
// can only be initialized with a value of type SomeProtocol
init<Base: SomeProtocol where Base.T == T>(_ base: Base) {
_doSomething = base.doSomething
}
func doSomething(something: T) {
_doSomething(something)
}
}
现在您使用 [AnySomeProtocol<T>]
类型的数组(将 T
替换为您想要的任何类型),并在附加元素之前将其转换为 AnySomeProtocol
:
var array = [AnySomeProtocol<String>]()
array.append(AnySomeProtocol(someType))
// doSomething can only be called with a string
array[0].doSomething("a string")
例如:
protocol SomeProtocol {
typealias T
func doSomething(something: T)
}
let a = Array<SomeProtocol>()
我想要一个数组,它是一个符合 SomeProtocol
的对象数组。这在理论上似乎很好,但我收到以下错误消息:
Cannot be used as a generic constraint because it contains assosciated type requirements.
我想这是有道理的,毕竟 Array 也是一个通用结构,所以编译器将无法弄清楚给定 SomeProtocol
和 [=14= 两者的实际类型是什么] 是通用的。
所以我的问题是 - 我觉得我应该能够拥有一组符合 SomeProtocol
的对象 - 目前在 Swift 2.0 中这可能吗?我是不是以完全错误的方式思考这个问题?
不,不可能像现在这样 Swift 2. 泛型类型只有在指定泛型参数后才能使用。对于泛型类、结构体和枚举,它们的泛型参数可以在使用时同时指定。例如一个数组可以这样使用:
let anArray: [String]
此处将Array
的泛型参数指定为String
,当Array
作为变量类型时
但是,泛型协议(具有关联类型的协议,命名为typealias)只有在具体类型符合它时才能指定其关联类型。当您使用泛型协议作为变量类型时,您无法提供关联类型,例如泛型 类、结构或枚举。
此错误消息的原因是如果您的 Array
声明有效,则会出现以下问题:
protocol SomeProtocol {
typealias T
func doSomething(something: T)
}
// has already some values
let a: Array<SomeProtocol> = [...]
// what type should be passed as parameter?
// the type of T in SomeProtocol is not defined
a[0].doSomething(...)
作为解决方法,您可以为任何类型的 SomeProtocol
创建一个通用包装器结构,这样您就可以指定 T
的类型(就像在 Swift 标准库 AnyGenerator、AnySequence 中一样, ...).
struct AnySomeProtocol<T>: SomeProtocol {
let _doSomething: T -> ()
// can only be initialized with a value of type SomeProtocol
init<Base: SomeProtocol where Base.T == T>(_ base: Base) {
_doSomething = base.doSomething
}
func doSomething(something: T) {
_doSomething(something)
}
}
现在您使用 [AnySomeProtocol<T>]
类型的数组(将 T
替换为您想要的任何类型),并在附加元素之前将其转换为 AnySomeProtocol
:
var array = [AnySomeProtocol<String>]()
array.append(AnySomeProtocol(someType))
// doSomething can only be called with a string
array[0].doSomething("a string")