我想将从通用类型派生的类的实例存储在字典中;也就是说,Dictionary 应该存储派生自该泛型的任何类的实例。
像这样:
class ParentClass {}
class ChildClass: ParentClass {}
class GenericClass<T: ParentClass> {
var foo:T?
}
typealias DerivedClass = GenericClass<ChildClass>
class TestGenerics {
var dict: Dictionary<String, GenericClass<**what goes here??**>> = [:]
func test() {
var derivedClassInstance = DerivedClass()
dict.updateValue(derivedClassInstance, forKey: "name")
}
}
这在 Java 中相当简单:
public class TestGenericsOuter {
class ParentClass {}
class ChildClass extends ParentClass {}
class GenericClass<T extends ParentClass> {
T foo;
}
class DerivedClass extends GenericClass<ChildClass> {}
class TestGenerics {
Dictionary<String, GenericClass<? extends ParentClass>> dict;
void test() {
DerivedClass derivedClassInstance = new DerivedClass();
dict.put("name", derivedClassInstance);
}
}
}
在 Swift 中可以实现这样的功能吗?我让它工作的唯一方法是创建一个以“Any”作为值类型的字典。但是,我失去了一些类型安全性,所以我想尽可能避免这种解决方案。
最佳答案
我认为您无法模仿 Java 的通配符,但您可能也不需要这样做。你可以只使用 ChildClass
无论代码在哪里期待 ParentClass
.所以使用你的例子:
class TestGenerics {
var dict: Dictionary<String, GenericClass<ParentClass>> = [:]
func test() {
var derivedClassInstance = GenericClass<ParentClass>()
dict.updateValue(derivedClassInstance, forKey: "name")
}
}
现在只需使用 ChildClass
填写foo
let test = TestGenerics()
test.test()
test.dict["name"]?.foo = ChildClass()
该代码编译没有错误。但是,Swift 不支持自定义泛型类的协变,因此您无法使用协变类型更改字典,因此以下代码无法编译:
test.dict = Dictionary<String, GenericClass<ChildClass>>()
//Error: 'ChildClass' is not identical to 'ParentClass'
这不是很直观,因为原生数组和字典确实支持协方差,所以这是允许的:
let array: Array<ParentClass> = Array<ChildClass>()
let dic: Dictionary<String, ParentClass> = Dictionary<String, ChildClass>()
但不是这个:
let generic: GenericClass<ParentClass> = GenericClass<ChildClass>()
//Error: 'ChildClass' is not identical to 'ParentClass'
基本上 Swift 对待 Array<ChildClass>
作为 Array<ParentClass>
的子类型但目前不可能告诉编译器 GenericClass<ChildClass>
是(或应该是)GenericClass<ParentClass>
的子类型.希望随着语言的发展,将添加一种将自定义类声明为协变的方法。
关于generics - Swift:使用通配符作为泛型类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25273260/