Swift Generic Factory:Bug? [英] Swift Generic Factory: Bug?

查看:159
本文介绍了Swift Generic Factory:Bug?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

研究Swift泛型,并绊倒一些非常奇怪的行为......我应该提交一个雷达,还是我在这里误解了一些东西?测试Swift 1.2 beta。



代码说得最好,简单的实现限制了工厂实例化BaseClass和派生类:

  ///测试工厂模式以实例化BaseClass并派生$ b $ class BaseClassFactory 
{
//总是返回BaseClass的一个实例,即使常量或
//存储结果的变量被明确地键入(见测试)
class func makeInstance< T:BaseClass>(类型:AnyClass) - > T'
{
return T()
}

//只有当存储
的常量或变量//结果是明确的时才返回DerivedClass的实例类型。
class func makeInstanceContrived< T:BaseClass>(类型:AnyClass) - > T'
{
让实例:T? = T.makeInstance()as? T
返回实例
}

//正常工作
类func makeInstanceAndCallBack< T:BaseClass>(handler:(instance:T?) - > Void) - >无效
{
let myInstance:T? = T.makeInstance()as? T

处理程序(实例:myInstance)
}
}

class BaseClass
{
//由于T()失败...
class func makeInstance() - > BaseClass
{
return BaseClass()
}
}

class DerivedClass :BaseClass
{
覆盖类func makeInstance() - > BaseClass
{
返回DerivedClass()
}
}

测试,带有非常奇怪行为的截图(尽管编译器警告,'is'测试通过):



<$ p $如果让实例= BaseClassFactory.makeInstance(DerivedClass.Type)
{
如果实例是DerivedClass == false
{
println(1:Wrong type ...)
}
}

//不用,即使输入常量也是如此。这似乎是非常危险的行为...
如果让实例:DerivedClass = BaseClassFactory.makeInstance(DerivedClass.Type)
{
如果实例是DerivedClass == false
{
//编译器甚至在这里给出一个警告:''是'test is always true
println(2:what ???)
}
}

//如果let contrivedInstance = BaseClassFactory.makeInstanceContrived(DerivedClass.Type)
{
如果contrivedInstance是DerivedClass == false
{
println(
) 3:错误的类型...)
}
}

//是的,输入常量在这里执行这个技巧
如果let contrivedInstance:DerivedClass = BaseClassFactory .makeInstanceContrived(DerivedClass.Type)
{
println(4:success!type is:\(contrivedInstance))
}

//是
BaseClassFactory.makeInstanceAndCallBack()
{
(instance:DerivedClass?) - >如果让callbackInstance = instance
{
println(5:success!type is:\(callbackInstance))
}
,则无效

}


解决方案

这里有两个问题 - 一个是不正确的代码,另一个是一个已知的bug(我的雷达被关闭为18518629,它仍然是从1.2b4开始的)。

首先,在这个结构中:

  class func makeInstance< T:BaseClass>(类型:AnyClass) - > T' 
{
return T()
}

//稍后

BaseClassFactory.makeInstance(DerivedClass.Type)

您的论点没有做任何事情。它基本上是毫无意义的,对 T 类型没有贡献(它怎么可能?参数没有引用 T )。相反, T 的类型将从上下文中选择,即如果您将结果赋值给 DerivedClass 变量, T 将会是 DerivedClass 。如果你没有指定,默认行为是让 T 它被约束的基类,即 BaseClass



您可能的意思是这样的:

  class func makeInstance< T:BaseClass>(类型:T.Type) - > T' 
{
return T()
}

//然后稍后

BaseClassFactory.makeInstance(DerivedClass.self)

这应该将 T 设定为类型你要。除非基类没有一个动态分配的初始化器(这个泛型只有一个运行时实现,它依赖于多态称为正确的初始化),否则它仍然无法工作。



如果您将所需的init(){} 添加到 BaseType 您会得到正确的行为。


Investigating Swift generics, and stumbling on some really odd behaviour... should I file a radar, or am I misunderstanding something here? Tested with Swift 1.2 beta.

Code speaks best, simple implementation which constrains the factory to instantiating BaseClass and derived classes:

/// Testing factory pattern to instantiate BaseClass and derived
class BaseClassFactory
{
    // Always returns an instance of BaseClass, even if the constant or
    // variable storing the result is explicitly typed( see test )
    class func makeInstance< T : BaseClass >( type: AnyClass ) -> T?
    {
        return T()
    }

    // Returns an instance of DerivedClass only if the constant or variable storing 
    // the result is explicitly typed.
    class func makeInstanceContrived< T : BaseClass >( type: AnyClass ) -> T?
    {
        let instance : T? = T.makeInstance() as? T
        return instance
    }

    // Works fine
    class func makeInstanceAndCallBack< T : BaseClass >( handler: ( instance: T? ) -> Void ) -> Void
    {
        let myInstance : T? = T.makeInstance() as? T

        handler( instance: myInstance )
    }
}

class BaseClass
{
    // Since T() fails... 
    class func makeInstance()->BaseClass
    {
        return BaseClass()
    }
}

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

Tests, with screenshot of very odd behaviour( despite the compiler warning, the 'is' test does pass ):

// Nope
if let instance = BaseClassFactory.makeInstance( DerivedClass.Type )
{
    if instance is DerivedClass == false
    {
        println( "1: Wrong type..." )
    }
}

// Nope, even when typing the constant. This seems like very dangerous behaviour...
if let instance : DerivedClass = BaseClassFactory.makeInstance( DerivedClass.Type )
{
    if instance is DerivedClass == false
    {
        //compiler even gives a warning here: " 'is' test is always true "
        println( "2: what the???" )
    }
}

// Nope
if let contrivedInstance = BaseClassFactory.makeInstanceContrived( DerivedClass.Type )
{
    if contrivedInstance is DerivedClass == false
    {
        println( "3: Wrong type..." )
    }
}

// Yes, typing the constant does the trick here
if let contrivedInstance : DerivedClass = BaseClassFactory.makeInstanceContrived( DerivedClass.Type )
{
    println( "4: success! type is: \(contrivedInstance )" )
}

// Yes
BaseClassFactory.makeInstanceAndCallBack()
{
    ( instance: DerivedClass? ) -> Void in

    if let callbackInstance = instance
    {
        println( "5: success! type is: \(callbackInstance )" )
    }
}

解决方案

You have two issues here – one is incorrect code, the other is a known bug (my radar of it was closed as a dup of 18518629 which is still open as of 1.2b4).

Firstly, in this construction:

class func makeInstance< T : BaseClass >( type: AnyClass ) -> T?
{
    return T()
}

// then later

BaseClassFactory.makeInstance( DerivedClass.Type )

your argument is not doing anything. It's essentially pointless and not contributing to the type of T (how could it? the argument does not reference T). Instead, the type of T will be chosen from context i.e. if you assign the result to a DerivedClass variable, T will be DerivedClass. If you don't specify, the default behavior is to make T the base class it's constrained to i.e. BaseClass.

What you probably mean is this:

class func makeInstance< T : BaseClass >( type: T.Type ) -> T?
{
    return T()
}

// then later

BaseClassFactory.makeInstance( DerivedClass.self )

This should do the trick of setting T to be the type you want. Except it still won't work, because of a bug caused by the base class not having a dynamically-dispatched initializer (there is only a single runtime implementation of the generic and it relies on the right init being called polymorphically).

If you add required init() { } to BaseType you'll get the correct behaviour.

这篇关于Swift Generic Factory:Bug?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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