使用约束类型参数实现 Swift 协议
Implementing Swift protocol with a constrained type parameter
我有几个 Swift 协议描述了我试图以多种方式实现的通用接口:
protocol Identifiable
{
var identifier:String { get }
}
protocol ItemWithReference
{
var resolveReference<T:Identifiable>(callback:(T) -> ())
}
现在我想使用 CloudKit 作为后端来实现 ItemWithReference
协议(这最终也将与备用后端一起工作,届时我希望提供一个替代方案ItemWithReference
协议的实施。
在我的 CloudKit 实现中,我有这样的东西:
class CloudKitIdentifiable : Identifiable
{
...
}
class CloudKitItemWithReference : ItemWithReference
{
func resolveReference<T:Identifiable>(callback:(T) -> ())
{
// In this implementation, I want to only proceed if `T` is a CloudKitIdentifiable subtype
// But not sure how to enforce that
}
}
我想做的是将 T
约束为 CloudKitIdentifiable
而不仅仅是简单的 Identifiable
。我不能直接在 resolveReference
声明中这样做,因为那样的话该函数将不符合 ItemWithReference
协议。因此,相反,我希望确认 T 确实是 CloudKitIdentifiable
,然后调用它的初始化程序来创建正在解析的 class 的新实例。
在 Swift 中有什么方法可以使用 T 的元类型 T.Type
并确定它是否是另一种类型的子类型?此外,是否有任何方法可以调用已在该子类型上声明的必需初始化程序?
尝试:
class CloudKitIdentifiable : Identifiable {
var identifier:String = ...
required init() {}
// you need `required`.
}
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if T.self is CloudKitIdentifiable.Type {
// do work..
let obj = (T.self as CloudKitIdentifiable.Type)()
callback(obj as T)
}
}
}
或:
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if let CKT = T.self as? CloudKitIdentifiable.Type {
// do work..
let obj = CKT()
callback(obj as T)
}
}
}
但是,在这种情况下,您必须这样调用 resolveReference
:
let ref = CloudKitItemWithReference()
ref.resolveReference { (obj: CloudKitIdentifiable) -> () in
// ^^^^^^^^^^^^^^^^^^^^ explicit type is necessary.
println(obj.identifier)
return
}
相比之下,我建议使用 Associated Type:
protocol Identifiable {
var identifier:String { get }
}
protocol ItemWithReference {
typealias Item: Identifiable // <-- HERE is associated type
func resolveReference(callback:(Item) -> ())
}
class CloudKitIdentifiable : Identifiable {
var identifier:String
init(identifier: String) {
self.identifier = identifier
}
}
class CloudKitItemWithReference : ItemWithReference {
// `Item` associated type can be inferred from
// the parameter type of `resolveReference()`
//
// typealias Item = CloudKitIdentifiable
func resolveReference(callback:(CloudKitIdentifiable) -> ()) {
let obj = CloudKitIdentifiable(identifier: "test")
callback(obj)
}
}
let ref = CloudKitItemWithReference()
ref.resolveReference { obj in
println(obj.identifier)
return
}
我有几个 Swift 协议描述了我试图以多种方式实现的通用接口:
protocol Identifiable
{
var identifier:String { get }
}
protocol ItemWithReference
{
var resolveReference<T:Identifiable>(callback:(T) -> ())
}
现在我想使用 CloudKit 作为后端来实现 ItemWithReference
协议(这最终也将与备用后端一起工作,届时我希望提供一个替代方案ItemWithReference
协议的实施。
在我的 CloudKit 实现中,我有这样的东西:
class CloudKitIdentifiable : Identifiable
{
...
}
class CloudKitItemWithReference : ItemWithReference
{
func resolveReference<T:Identifiable>(callback:(T) -> ())
{
// In this implementation, I want to only proceed if `T` is a CloudKitIdentifiable subtype
// But not sure how to enforce that
}
}
我想做的是将 T
约束为 CloudKitIdentifiable
而不仅仅是简单的 Identifiable
。我不能直接在 resolveReference
声明中这样做,因为那样的话该函数将不符合 ItemWithReference
协议。因此,相反,我希望确认 T 确实是 CloudKitIdentifiable
,然后调用它的初始化程序来创建正在解析的 class 的新实例。
在 Swift 中有什么方法可以使用 T 的元类型 T.Type
并确定它是否是另一种类型的子类型?此外,是否有任何方法可以调用已在该子类型上声明的必需初始化程序?
尝试:
class CloudKitIdentifiable : Identifiable {
var identifier:String = ...
required init() {}
// you need `required`.
}
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if T.self is CloudKitIdentifiable.Type {
// do work..
let obj = (T.self as CloudKitIdentifiable.Type)()
callback(obj as T)
}
}
}
或:
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if let CKT = T.self as? CloudKitIdentifiable.Type {
// do work..
let obj = CKT()
callback(obj as T)
}
}
}
但是,在这种情况下,您必须这样调用 resolveReference
:
let ref = CloudKitItemWithReference()
ref.resolveReference { (obj: CloudKitIdentifiable) -> () in
// ^^^^^^^^^^^^^^^^^^^^ explicit type is necessary.
println(obj.identifier)
return
}
相比之下,我建议使用 Associated Type:
protocol Identifiable {
var identifier:String { get }
}
protocol ItemWithReference {
typealias Item: Identifiable // <-- HERE is associated type
func resolveReference(callback:(Item) -> ())
}
class CloudKitIdentifiable : Identifiable {
var identifier:String
init(identifier: String) {
self.identifier = identifier
}
}
class CloudKitItemWithReference : ItemWithReference {
// `Item` associated type can be inferred from
// the parameter type of `resolveReference()`
//
// typealias Item = CloudKitIdentifiable
func resolveReference(callback:(CloudKitIdentifiable) -> ()) {
let obj = CloudKitIdentifiable(identifier: "test")
callback(obj)
}
}
let ref = CloudKitItemWithReference()
ref.resolveReference { obj in
println(obj.identifier)
return
}