2014-10-09 93 views
17

我试图根据指定的泛型类型转换和/或生成一个变量。我知道在swift中没有类型擦除,但似乎并不像泛型所指定的一般条件那样保留类型。符合基类。似乎所有我可以施放或初始化的都是基础类。什么是更奇怪的是,当我在调试器是通用似乎有一个RawPointer到正确的类甚至变量看起来他们是在正确的类型:快速仿制药不保存类型

编辑:

由于的Xcode 6.1的这仍是一个问题(格雷戈里希格利的简化代码提供):

class BaseClass { 
    func printme() -> Void { 
     println("I am BaseClass") 
    } 
} 

class DerivedClass : BaseClass { 
    override func printme() -> Void { 
     println("I am DerivedClass") 
    } 
} 

class Util<T: BaseClass> { 
    func doSomething() { 
     var instance = T() 
     instance.printme() 
    } 
} 

var util = Util<DerivedClass>() 
util.doSomething() 

仍然打印出“我的BaseClass”

另外要注意的是需要初始化{}在基础CLAS s不再有效。

enter image description here

+0

您应该更改rintaro的正确答案。 – 2014-10-09 17:40:37

+0

@rfrittelli - 其实正确的答案是JeremyP的。我已经证实它的工作原理,而rintaro的答案不再适用于最新的XCode。 – Lee 2014-10-16 16:25:59

+0

你的原始输出是什么(它会有帮助)?从6.1开始,两个测试都会得到相同的结果,这是预期的结果。你也可以陈述你的问题吗? – 2014-11-13 02:35:31

回答

15

此代码按预期工作。

class BaseClass { 

    required init() {} // <-- ADDED THIS 

    func printme() -> Void { 
     println("I am BaseClass") 
    } 
} 

class DerivedClass : BaseClass { 
    override func printme() -> Void { 
     println("I am DerivedClass") 
    } 
} 

class Util<T: BaseClass> { 
    func doSomething() { 
     var instance = T() 
     instance.printme() 
    } 
} 

var util = Util<DerivedClass>() 
util.doSomething() 

代码库是从@GregoryHigley答案:)

标记init() {}required做的东西被盗。 这保证了init()的任何指定初始值设定项从BaseClass的任何派生类。

没有它,可以使非法的子类,如:

class IllegalDerivedClass : BaseClass { 
    var name:String 

    init(name:String) { 
     self.name = name 
     super.init() 
    } 

    override func printme() -> Void { 
     println("I am DerivedClass") 
    } 
} 

var util = Util<IllegalDerivedClass>() 
util.doSomething() 

你知道这并不因为IllegalDerivedClassdoesn't inherit init() initializer工作。

我想,这是你的问题的原因。

无论如何,谁的错?

  • 编译器应警告模糊性。
  • 运行时间应尝试初始化DerivedClass(),如T所述。
  • 调试器应该显示instanceBaseClass的一个实例,因为它实际上是。

新增:

作为的Xcode 6.1通用汽车2,看来,你需要更多的工作。 (除required init() {}

class Util<T: BaseClass> { 
    let theClass = T.self // store type itself to variable 

    func doSomething() { 
     var instance = theClass() // then initialize 
     instance.printme() 
    } 
} 

我完全不知道为什么我们需要这个,这是怎么回事X(

新增:二○一四年十月一十八日

我发现这也适用:

func doSomething() { 
     var instance = (T.self as T.Type)() 
     instance.printme() 
    } 

新增:2015年2月10日

随着版本的Xcode 6.3(6D520o)的/雨燕1.2

我们不再需要(T.self as T.Type)()破解。只要T()工作,只要Trequired init()初始值设定项。

class Util<T: BaseClass> { 
    func doSomething() { 
     var instance = T() 
     instance.printme() 
    } 
} 
+0

这应该被标记为正确的答案。可悲的是,尽管如此,我仍然认为这是一个错误,因为它违反了最不让人惊讶的原则。让它正确工作需要专业知识,而这些知识不应该是必需的。 – 2014-10-09 17:39:32

+0

很酷的很好的答案。但我同意这仍然是一个错误。 – rfrittelli 2014-10-09 18:03:23

+0

-1因为它不适用于最新的XCode(6.1 GM2),我认为@ JeremyP的答案是有效的。 – Lee 2014-10-16 15:08:48

6

我创建你的代码的简化版本如下:

class BaseClass { 
    func printme() -> Void { 
     println("I am BaseClass") 
    } 
} 

class DerivedClass : BaseClass { 
    override func printme() -> Void { 
     println("I am DerivedClass") 
    } 
} 

class Util<T: BaseClass> { 
    func doSomething() { 
     var instance = T() 
     instance.printme() 
    } 
} 

var util = Util<DerivedClass>() 
util.doSomething() 

此提炼问题,以它的本质。人们会期望util.doSomething()打印“我是DerivedClass”,但它每次打印“我是BaseClass”。这必须是一个错误,因为没有理性的类型系统会以这种方式工作。

我认为你应该将这个文件作为一个错误提交给Apple。

+1

对不起,我的混乱的例子,但这正是我的想法。谢谢,并会做。 – rfrittelli 2014-10-09 14:14:17

+0

当你提交错误时,请使用我的例子而不是你的例子,因为它更直截了当。 (没有必要的信用,毕竟你发现了这个错误。) – 2014-10-09 14:40:58

+0

我确实使用过你的:)。再次感谢! – rfrittelli 2014-10-09 14:48:38

4

问题是var instance = T()初始化程序不是虚拟的,因此实例始终由BaseClass()*组成。下面的代码使用一个类函数来解决此问题:

class BaseClass { 
    func printme() -> String { 
     return "I am BaseClass" 
    } 
    class func makeInstance() -> BaseClass 
    { 
     return BaseClass() 
    } 
} 

class DerivedClass : BaseClass { 
    override class func makeInstance() -> BaseClass 
    { 
     return DerivedClass() 
    } 

    override func printme() -> String { 
     return "I am DerivedClass" 
    } 
} 

class Util<T: BaseClass> { 
    func doSomething() -> String { 
     var instance = T.makeInstance() 
     return instance.printme() 
    } 
} 

var util = Util<DerivedClass>() 
println("\(util.doSomething())") 

我改变了printme()实施只是因为原来的代码并没有因为某些原因游乐场打印任何。

*我认为这仍然是一个错误。

+1

我曾想过这件事......但对我来说,它似乎仍然破裂。为什么这个类型不能推断自己并且自己调用init? – rfrittelli 2014-10-09 15:50:04

+0

@rfrittelli我认为这也是一个错误。我只是在解释这个错误是什么。恕我直言 – JeremyP 2014-10-09 15:51:27

+0

是的,人们不应该为了做到这一点而跳过这些箍筋。它违反了“最不可思议的原则”。我对Swift的类型系统有很多批评,尤其是涉及泛型和扩展的地方。似乎有很多“减速带”。 – 2014-10-09 15:57:26

1

我有类似的问题。您需要添加required初始化程序和let realType = T.self并用realType()替换T()

class BaseClass { 
    required init() {} 
    func printme() -> Void { 
     println("I am BaseClass") 
    } 
} 

class DerivedClass : BaseClass { 
    override func printme() -> Void { 
     println("I am DerivedClass") 
    } 
} 

class Util<T: BaseClass> { 
    func doSomething() { 
     let realType = T.self // that's it 
     var instance = realType() 
     instance.printme() 
    } 
} 

var util = Util<DerivedClass>() 
util.doSomething()