【问题标题】:Swift Generic Factory: Bug?Swift 通用工厂:错误?
【发布时间】:2015-04-07 20:12:35
【问题描述】:

调查 Swift 泛型,并偶然发现一些非常奇怪的行为......我应该提交雷达,还是我在这里误解了什么?使用 Swift 1.2 beta 测试。

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

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

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

// 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 )" )
    }
}

【问题讨论】:

    标签: swift generics factory


    【解决方案1】:

    这里有两个问题——一个是不正确的代码,另一个是一个已知的错误(我的雷达作为 18518629 的副本已关闭,截至 1.2b4 仍处于打开状态)。

    首先,在这个结构中:

    class func makeInstance< T : BaseClass >( type: AnyClass ) -> T?
    {
        return T()
    }
    
    // then later
    
    BaseClassFactory.makeInstance( DerivedClass.Type )
    

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

    你的意思可能是这样的:

    class func makeInstance< T : BaseClass >( type: T.Type ) -> T?
    {
        return T()
    }
    
    // then later
    
    BaseClassFactory.makeInstance( DerivedClass.self )
    

    这应该可以将T 设置为您想要的类型。除非它仍然无法工作,因为基类没有动态分派的初始化程序导致的错误(泛型只有一个运行时实现,它依赖于以多态方式调用正确的 init)。

    如果您将required init() { } 添加到BaseType,您将获得正确的行为。

    【讨论】:

    • 非常感谢。我从 T.Type 作为参数开始,除了它在没有必需的 init 的情况下无法工作......因为测试 4 通过了,我假设编译器能够根据 AnyClass.Type 推断类型,它看起来有点像(一些帮助)。
    猜你喜欢
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多