Swift泛型不保存类型 [英] Swift generics not preserving type

查看:95
本文介绍了Swift泛型不保存类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



<编辑:



从Xcode 6.1开始,这仍然是一个问题(简单的代码由Gregory Higley提供):

  class BaseClass {
func printme() - >无效{
println(我是BaseClass)
}
}
$ b $ class DerivedClass:BaseClass {
override func printme() - > Void {
println(我是DerivedClass)
}
}

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

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

BaseClass



还要注意,基类中必需的init {}不再有效。



解决方案



  class BaseClass {

需要init() {} //< - 添加了这个$​​ b
$ b func printme() - >无效{
println(我是BaseClass)
}
}
$ b $ class DerivedClass:BaseClass {
override func printme() - > Void {
println(我是DerivedClass)
}
}

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

var util =使用< DerivedClass>()
util.doSomething()


$ b

init(){} 标记为必需做了这件事。
这保证 init()是从 BaseClass ANY 派生类的指定初始值设定项如果没有它,可以创建非法的子类:

  class IllegalDerivedClass:BaseClass {
var name:String

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

覆盖func printme() - > Void {
println(我是DerivedClass)
}
}

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

您知道这是行不通的,因为 IllegalDerivedClass 不会继承 init()初始值设定项



我认为这就是您的问题。 / p>

无论如何,是谁的错?


  • 编译器应警告模糊不清。
  • 运行时应该尝试初始化 DerivedClass() c $ c> T

  • 调试器应显示实例 BaseClass 的实例,因为它实际上是。





ADDED:



从Xcode 6.1 GM 2开始,似乎需要更多的工作。 (除了需要init(){}

  class Util< ; T:BaseClass> {
让theClass = T.self //将自己的类型存储到变量

func doSomething(){
var instance = theClass()//然后初始化
instance .printme()
}
}

我完全不知道为什么我们需要这个,发生了什么X(



ADDED:2014/10/18



我发现这也适用:
$ b $ pre $ func doSomething(){
var instance =(T.self as T.Type)()
instance.printme()
}






<从Xcode版本6.3(6D520o)/ Swift 1.2开始



我们不再需要(T.self作为T.Type)() hack,只需 T()只要 T 具有所需的init()初始值设定项。

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


I'm trying cast and/or generate a variable based upon the specified generic type. I understand there is no type erasure in swift, but it doesn't seem like the generics preserve type other than the specified conditions of the generic e.g. conforming to a base class. It seems like all i can cast or initialize is the base class. What's even more strange is when i'm in the debugger the generic appears to have a RawPointer to the correct class and even the variables look like they're of the right type:

EDIT:

As of Xcode 6.1 this is still an issue (simplified code courtesy of Gregory Higley) :

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()

Still prints out "I am BaseClass"

Also would like to note that required init{} in the base class no longer works.

解决方案

This code works as expected.

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()

Code base are stolen from @GregoryHigley answer :)

Marking init() {} as required did the thing. This guarantees init() is the designated initializer of ANY derived class from BaseClass.

Without it, one can make illegal subclass like:

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()

You know this doesn't work because IllegalDerivedClass doesn't inherit init() initializer.

I think, that is the reason of your problem.

Anyway, whose fault is that?

  • Compiler should warn about ambiguousness.
  • Runtime should try to initialize DerivedClass() as specified with T.
  • Debugger should show instance is a instance of BaseClass as it actually is.

ADDED:

As of Xcode 6.1 GM 2, It seems, you need more work. (in addition to required init() {})

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

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

I have absolutely no idea why we need this, what's going on X(

ADDED:2014/10/18

I found this also works:

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


ADDED: 2015/02/10

As of Xcode Version 6.3 (6D520o) / Swift 1.2

We no longer need (T.self as T.Type)() hack. Just T() works as long as T has required init() initializer.

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

这篇关于Swift泛型不保存类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆