为什么在 Swift 泛型工厂方法中编译器会警告泛型 class 'X' 要求 'Object' 符合 'Y'
Why in Swift generics factory method does compiler warn Generic class 'X' requires that 'Object' conforms to 'Y'
总的来说,我正在尝试在 Swift 中实现数据抽象层。我正在使用两个数据库 SDK,但我试图将它们的特定 API 与系统的其余部分隔离开来。
我正在尝试实现一个工厂模式,它将 return 基于提供的具体类型的协议一致性的正确对象。但是编译器给了我一些危险信号,我无法理解。
Thing
class 是第一个 class 实体,它可以在应用程序的逻辑层和 UI 层中自由移动,并且某些对象会保留在 Realm 存储中(这应该无关紧要)并且具有特定类型,即 Realm 对象的子class。该类型 return 由静态函数编辑,该函数必须存在以符合 FromDataSourceA 协议。
protocol FromDataSourceA {
static func A_objectType () -> A_Object.Type
}
class MyObject {
...
}
class Thing: MyObject, FromDataSourceA {
static func A_objectType () -> A_Thing.Type
...
}
// Example usage
let target = DataTarget<Thing>(url: "url")
let dataSource = target.dataSourceBuilder()
如您所见,具体类型 Thing
符合 FromDataSourceA
并被传递到 DataTarget
初始化程序。 DataSourceBuilder
需要能够检查 Thing
是否符合 FromDataSourceA
才能 return 正确的 DataSource
.
DataSourceTypeA class 看起来像
class DataSourceTypeA<T: MyObject & FromDataSourceA>: DataSource<T> {
let db: DatabaseTypeA // All db-specific APIs contained here
override init (target: DataTarget<T>) {
self.db = try! DatabaseTypeA()
super.init(target: target)
}
override func create<T: MyObject & FromDataSourceA> (object: T) {
db.beginWrite()
db.create(T.A_objectType(), value: object.dict()) // <-- T.A_objectType() is what the conformance to FromDataSourceA is needed for
try! db.commitWrite()
}
override func get<T: MyObject & FromDataSourceA>(id: Int) -> T {
...
}
}
class DataSource<T>: AnyDataSource {
let target: DataTarget<T>
init (target: DataTarget<T>) {
self.target = target
}
func create<T> (object: T) { }
func get<T>(id: Int) -> T { fatalError("get(id:) has not been implemented") }
}
protocol AnyDataSource {
func create<T> (object: T)
func get<T> (id: Int) -> T
}
我现在面临的问题是当我检查元类型是否符合 FromDataSourceA 时,编译器给我这个警告
class DataTarget<T: MyObject> {
...
func dataSourceBuilder () -> DataSource<T> {
if T.self is FromDataSourceA { // <-- Thing.self conforms to FromDataSourceA
// The Problem:
return DataSourceTypeA(target: self) // Generic class 'DataSourceTypeA' requires that 'MyObject' conform to 'FromDataSourceA'
} else {
...
}
}
}
如果泛型 T
通过条件语句并被证明在符合 FromDataSourceA
?
问题是调用
return DataSourceTypeA(target: self)
在编译时解决,因此无助于检查
if T.self is FromDataSourceA { }
在运行时。一个可能的解决方案是通过定义一个受限扩展使一致性检查成为编译时检查:
extension DataTarget where T: FromDataSourceA {
func dataSourceBuilder() -> DataSource<T> {
return DataSourceTypeA(target: self)
}
}
如有必要,您可以为其他限制添加更多实现:
extension DataTarget where T: FromDataSourceB {
func dataSourceBuilder() -> DataSource<T> {
// ...
}
}
或添加默认实现:
extension DataTarget {
func dataSourceBuilder() -> DataSource<T> {
// ...
}
}
来电
let dataSource = target.dataSourceBuilder()
编译器将根据 target
的静态(编译时)类型信息选择最具体的实现。
总的来说,我正在尝试在 Swift 中实现数据抽象层。我正在使用两个数据库 SDK,但我试图将它们的特定 API 与系统的其余部分隔离开来。
我正在尝试实现一个工厂模式,它将 return 基于提供的具体类型的协议一致性的正确对象。但是编译器给了我一些危险信号,我无法理解。
Thing
class 是第一个 class 实体,它可以在应用程序的逻辑层和 UI 层中自由移动,并且某些对象会保留在 Realm 存储中(这应该无关紧要)并且具有特定类型,即 Realm 对象的子class。该类型 return 由静态函数编辑,该函数必须存在以符合 FromDataSourceA 协议。
protocol FromDataSourceA {
static func A_objectType () -> A_Object.Type
}
class MyObject {
...
}
class Thing: MyObject, FromDataSourceA {
static func A_objectType () -> A_Thing.Type
...
}
// Example usage
let target = DataTarget<Thing>(url: "url")
let dataSource = target.dataSourceBuilder()
如您所见,具体类型 Thing
符合 FromDataSourceA
并被传递到 DataTarget
初始化程序。 DataSourceBuilder
需要能够检查 Thing
是否符合 FromDataSourceA
才能 return 正确的 DataSource
.
DataSourceTypeA class 看起来像
class DataSourceTypeA<T: MyObject & FromDataSourceA>: DataSource<T> {
let db: DatabaseTypeA // All db-specific APIs contained here
override init (target: DataTarget<T>) {
self.db = try! DatabaseTypeA()
super.init(target: target)
}
override func create<T: MyObject & FromDataSourceA> (object: T) {
db.beginWrite()
db.create(T.A_objectType(), value: object.dict()) // <-- T.A_objectType() is what the conformance to FromDataSourceA is needed for
try! db.commitWrite()
}
override func get<T: MyObject & FromDataSourceA>(id: Int) -> T {
...
}
}
class DataSource<T>: AnyDataSource {
let target: DataTarget<T>
init (target: DataTarget<T>) {
self.target = target
}
func create<T> (object: T) { }
func get<T>(id: Int) -> T { fatalError("get(id:) has not been implemented") }
}
protocol AnyDataSource {
func create<T> (object: T)
func get<T> (id: Int) -> T
}
我现在面临的问题是当我检查元类型是否符合 FromDataSourceA 时,编译器给我这个警告
class DataTarget<T: MyObject> {
...
func dataSourceBuilder () -> DataSource<T> {
if T.self is FromDataSourceA { // <-- Thing.self conforms to FromDataSourceA
// The Problem:
return DataSourceTypeA(target: self) // Generic class 'DataSourceTypeA' requires that 'MyObject' conform to 'FromDataSourceA'
} else {
...
}
}
}
如果泛型 T
通过条件语句并被证明在符合 FromDataSourceA
?
问题是调用
return DataSourceTypeA(target: self)
在编译时解决,因此无助于检查
if T.self is FromDataSourceA { }
在运行时。一个可能的解决方案是通过定义一个受限扩展使一致性检查成为编译时检查:
extension DataTarget where T: FromDataSourceA {
func dataSourceBuilder() -> DataSource<T> {
return DataSourceTypeA(target: self)
}
}
如有必要,您可以为其他限制添加更多实现:
extension DataTarget where T: FromDataSourceB {
func dataSourceBuilder() -> DataSource<T> {
// ...
}
}
或添加默认实现:
extension DataTarget {
func dataSourceBuilder() -> DataSource<T> {
// ...
}
}
来电
let dataSource = target.dataSourceBuilder()
编译器将根据 target
的静态(编译时)类型信息选择最具体的实现。