【发布时间】:2014-12-19 18:00:34
【问题描述】:
基于上一个已解决的问题,但它导致了另一个问题。如果协议/类类型存储在集合中,则检索并实例化它们会引发错误。下面是一个假设的例子。该范例基于“Program to Interface not an implementation”What does it mean to "program to an interface"?
instantiate from protocol.Type reference dynamically at runtime
public protocol ISpeakable {
init()
func speak()
}
class Cat : ISpeakable {
required init() {}
func speak() {
println("Meow");
}
}
class Dog : ISpeakable {
required init() {}
func speak() {
println("Woof");
}
}
//Test class is not aware of the specific implementations of ISpeakable at compile time
class Test {
func instantiateAndCallSpeak<T: ISpeakable>(Animal:T.Type) {
let animal = Animal()
animal.speak()
}
}
// Users of the Test class are aware of the specific implementations at compile/runtime
//works
let t = Test()
t.instantiateAndCallSpeak(Cat.self)
t.instantiateAndCallSpeak(Dog.self)
//doesn't work if types are retrieved from a collection
//Uncomment to show Error - IAnimal.Type is not convertible to T.Type
var animals: [ISpeakable.Type] = [Cat.self, Dog.self, Cat.self]
for animal in animals {
//t.instantiateAndCallSpeak(animal) //throws error
}
for (index:Int, value:ISpeakable.Type) in enumerate(animals) {
//t.instantiateAndCallSpeak(value) //throws error
}
编辑 - 我当前的解决方法是遍历集合,但当然它是有限的,因为 api 必须知道各种实现。另一个限制是这些类型的子类(例如 PersianCat、GermanShepherd)不会调用它们的覆盖函数,或者我去 Objective-C 进行救援(NSClassFromString 等)或等待 SWIFT 支持此功能。
注意(背景):这些类型由实用程序的用户推送到数组中,并在通知时执行 for 循环
var animals: [ISpeakable.Type] = [Cat.self, Dog.self, Cat.self]
for Animal in animals {
if Animal is Cat.Type {
if let AnimalClass = Animal as? Cat.Type {
var instance = AnimalClass()
instance.speak()
}
} else if Animal is Dog.Type {
if let AnimalClass = Animal as? Dog.Type {
var instance = AnimalClass()
instance.speak()
}
}
}
【问题讨论】:
-
这是一种设计模式/哲学,与 Java、.NET - C# 等、ActionScript 等无关
-
我知道。但它在许多 Java 书籍中经常被提及,因此有评论。
-
我明白了,我被阻止了,棺材上的最后一颗钉子,我完成了,构建了一些设计模式实用程序,我也就此联系了 Chris Lattner,你认为这是编译器的错误?
-
问题是什么?
-
顺便说一句,该系列是一个红鲱鱼。问题在于“超类型”。只需说
let Speaker : ISpeakable.Type = Cat.self; t.instantiateAndCallSpeak(Speaker),您就可以更简单地得到相同的错误
标签: swift generic-programming generic-collections