如何使用Swift字典存储泛型对象[T:C<;T>;]?
我很难使用Swift字典来存储通用对象 我尝试以下列方式存储对象:如何使用Swift字典存储泛型对象[T:C<;T>;]?,swift,dictionary,generics,subscript,Swift,Dictionary,Generics,Subscript,我很难使用Swift字典来存储通用对象 我尝试以下列方式存储对象: [C: Container<C>], where C: ContentType 我有许多不同的“ContentType”子类,每个子类描述一种特定类型的内容 class ContentTypeA: ContentType { ... } class ContentTypeB: ContentType { ... } 容器 我还有一个名为“Container”的类,用于存储与内容类型相关的信息。恰当地说,它是一个泛
[C: Container<C>], where C: ContentType
我有许多不同的“ContentType”子类,每个子类描述一种特定类型的内容
class ContentTypeA: ContentType { ... }
class ContentTypeB: ContentType { ... }
容器
我还有一个名为“Container”的类,用于存储与内容类型相关的信息。恰当地说,它是一个泛型类,其泛型类型为“ContentType”
控制器
在我的主控制器类中,我实现了以下下标重载
subscript<C: ContentType>(contentType: C) -> Container<C> {
// If Container for ContentType "C" does not exist
if (self.containers[contentType] == nil) {
// Then create it
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
}
// And return it
return self.containers[contentType]! as! Container<C>
}
从这里,可以调用特定于每个ContentType的容器扩展
class Container<C: ContentType>: NSObject { }
extension Container where C: ContentTypeA {
func fancyFunctionOnlyFoundInContentTypeA() { }
}
extension Container where C: ContentTypeB {
func fancyFunctionOnlyFoundInContentTypeB() { }
}
containerForTypeA.fancyFunctionOnlyFoundInContentTypeA()
containerForTypeB.fancyFunctionOnlyFoundInContentTypeB()
问题
我相信所有这些在理论上都是可行的,而且它确实可以在Swift 4、Xcode 9.0中编译。但是,在执行以下操作时:
// Then create it
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
//然后创建它
self.containers[contentType]=(Container.init()作为!Container)
我得到以下错误:
Could not cast value of type 'Test.Container<Test.ContentTypeA>' (0x109824a00) to 'Test.Container<Test.ContentType>' (0x109824638).
无法将“Test.Container”(0x109824a00)类型的值强制转换为“Test.Container”(0x109824638)。
由于ContentTypeA继承自ContentType,我不理解为什么这是一个问题。Swift字典似乎无法存储ContentType类ViewController:UIViewController{
var containers=[ContentType:Container]()
重写func viewDidLoad(){
super.viewDidLoad()
设contentTypeA=contentTypeA.init()
让contentTypeB=contentTypeB.init()
让containerForTypeA=self[contentTypeA]
让containerForTypeB=self[contentTypeB]
containerForTypeA.fancyFunctionOnlyFoundInContentTypeA()
containerForTypeB.fancyFunctionOnlyFoundInContentTypeB()中
}
下标(contentType:C)->容器{
if(self.containers[contentType]==nil){
self.containers[contentType]=(Container.init()作为!Container)
}
返回self.containers[contentType]!as!Container
}
}
类ContentType:NSObject{}
类容器:NSObject{}
类ContentTypeA:ContentType{}
类ContentTypeB:ContentType{}
扩展容器,其中C:ContentTypeA{
func fancyFunctionOnlyFoundInContentTypeA(){}
}
扩展容器,其中C:ContentTypeB{
func fancyFunctionOnlyFoundInContentTypeB(){}
}
发生崩溃是因为Swift泛型是不变的,因此容器
不是容器
的子类,即使B
将是a
的子类,任何向下转换都将失败,强制转换将导致崩溃
您可以通过在字典中使用AnyObject
作为基类来解决这个问题,因为Container
是从NSObject
派生的:
var containers = [ContentType : AnyObject]()
subscript<C: ContentType>(contentType: C) -> Container<C> {
if let container = containers[contentType] {
return container as! Container<C>
} else {
let container = Container<C>()
containers[contentType] = container
return container
}
}
var containers=[ContentType:AnyObject]()
下标(contentType:C)->容器{
如果let container=containers[contentType]{
将容器作为!容器返回
}否则{
let container=container()
容器[contentType]=容器
返回容器
}
}
Swift是否支持逆变泛型(和相关类型转换)?Test.Container
基本上与Test.Container无关,因为泛型是不变的。考虑一个<代码>设置>代码> TEX>代码>测试。容器< /代码>设置泛型类型的变量:如果将容器“uppe”到一个更一般的泛型,那么调用该类的实例,那么会发生什么?然后继续使用uncasted对象,变量现在会有什么值?应该这样做;)接下来,如果这段代码变得更复杂,那么创建一个非泛型的容器
超类也可能值得考虑。谢谢Cristik(很抱歉回复太慢)!您的解决方案工作得非常出色,但我已经放弃了在本例中使用泛型的尝试,因为它们被证明比它们的价值更麻烦。干杯@LukeFletcher是的,有时泛型会增加不必要的复杂性,如果类型安全可以通过更传统的方式实现,那么建议采用这些方式。
// Then create it
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
Could not cast value of type 'Test.Container<Test.ContentTypeA>' (0x109824a00) to 'Test.Container<Test.ContentType>' (0x109824638).
class ViewController: UIViewController {
var containers = [ContentType : Container<ContentType>]()
override func viewDidLoad() {
super.viewDidLoad()
let contentTypeA = ContentTypeA.init()
let contentTypeB = ContentTypeB.init()
let containerForTypeA = self[contentTypeA]
let containerForTypeB = self[contentTypeB]
containerForTypeA.fancyFunctionOnlyFoundInContentTypeA()
containerForTypeB.fancyFunctionOnlyFoundInContentTypeB()
}
subscript<C: ContentType>(contentType: C) -> Container<C> {
if (self.containers[contentType] == nil) {
self.containers[contentType] = (Container<C>.init() as! Container<ContentType>)
}
return self.containers[contentType]! as! Container<C>
}
}
class ContentType: NSObject { }
class Container<C: ContentType>: NSObject { }
class ContentTypeA: ContentType { }
class ContentTypeB: ContentType { }
extension Container where C: ContentTypeA {
func fancyFunctionOnlyFoundInContentTypeA() { }
}
extension Container where C: ContentTypeB {
func fancyFunctionOnlyFoundInContentTypeB() { }
}
var containers = [ContentType : AnyObject]()
subscript<C: ContentType>(contentType: C) -> Container<C> {
if let container = containers[contentType] {
return container as! Container<C>
} else {
let container = Container<C>()
containers[contentType] = container
return container
}
}