为什么编译器在Swift泛型工厂方法中警告泛型类';X';要求';对象';符合';Y';
总而言之,我正在尝试用Swift实现一个数据抽象层。我使用了两个数据库SDK,但我试图将它们的特定API与系统的其余部分隔离开来 我试图实现一个工厂模式,该模式将根据提供的具体类型的协议一致性返回正确的对象。但是编译器给了我一些我无法理解的危险信号为什么编译器在Swift泛型工厂方法中警告泛型类';X';要求';对象';符合';Y';,swift,generics,factory,Swift,Generics,Factory,总而言之,我正在尝试用Swift实现一个数据抽象层。我使用了两个数据库SDK,但我试图将它们的特定API与系统的其余部分隔离开来 我试图实现一个工厂模式,该模式将根据提供的具体类型的协议一致性返回正确的对象。但是编译器给了我一些我无法理解的危险信号 Thing类是一个一级实体,可以在应用程序的逻辑层和UI层中自由移动,某些对象保存在领域存储中(这不重要),并且具有领域对象的子类的特定类型。该类型由一个静态函数返回,该函数必须存在以符合来自DataSourcea的协议 protocol FromD
Thing
类是一个一级实体,可以在应用程序的逻辑层和UI层中自由移动,某些对象保存在领域存储中(这不重要),并且具有领域对象的子类的特定类型。该类型由一个静态函数返回,该函数必须存在以符合来自DataSourcea的协议
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()
我现在面临的问题是,当我检查元类型是否符合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 {
...
}
}
}
类数据目标{
...
func dataSourceBuilder()->DataSource{
如果T.self来自datasourcea{/,那么问题是调用
return DataSourceTypeA(target: self)
在编译时解析,因此检查没有帮助
if T.self is FromDataSourceA { }
运行时。一种可能的解决方案是通过定义受限扩展,将一致性检查作为编译时检查:
extension DataTarget where T: FromDataSourceA {
func dataSourceBuilder() -> DataSource<T> {
return DataSourceTypeA(target: self)
}
}
编译器将根据target
的静态(编译时)类型信息选择最具体的实现,我有点担心短语“编译器将在解析对该函数的调用时选择最具体的实现”会给人一种印象,带有where子句的多个扩展将作为动态分派和/或函数重载的一种替代。很多人希望这种情况会发生,然后在运行时惊讶于它不会发生(即调用函数的“错误”版本)。谢谢你回答@Martin。我在受限扩展上的约束中添加了MyObject
,它正在工作。@matt谢谢你的评论-我会保持警惕,并尝试花更多的时间研究这个问题。@Martin可能。:)我可能不必要地担心。毕竟,你说的是“编译器”,这就是重点。只是我看到很多问题,人们试图滥用where子句,比如:还有我的
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()