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")