【问题标题】:Swift error with generic array通用数组的 Swift 错误
【发布时间】:2015-02-28 21:15:46
【问题描述】:

我有一个非常简单的游乐场:

protocol MyProtocol {}

struct MyType: MyProtocol {}

class MyClass <T: MyProtocol> {
    func myFunction(array: [T]) {
        if let myArray = array as? [MyType] {
            println("Double!")
        }
    }
}

let instance = MyClass<MyType>()

let array = [MyType(), MyType()]

instance.myFunction(array)

然后它在if let 行上显示“MyType is not a subtype of 'T'”。不过,我认为MyTypeT 是兼容的。

当我修改if let 语句时,它确实有效:

if let first = array.first as? MyType

但现在我不能将 array 转换为 [MyType](当然,我知道这是 Swift 的静态类型规范。)

我想知道问题出在哪里。我对泛型的理解?还是 Swift 语言的限制?如果是这样,有什么办法可以这样做吗?

提前致谢。

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    Swift 没有内置的行为来推测性地将数组的内容从一种任意类型转换为另一种。它只会对它知道具有子类型/超类型关系的两种类型执行此操作:

    class A { }
    class B: A { }
    let a: [A] = [B(),B()]
    // this is allowed - B is a subtype of A
    let b = a as? [B]
    
    let a: [AnyObject] = [1,2,3]
    // this is allowed - NSNumber is a subtype of AnyObject
    let b = a as? [NSNumber]
    
    struct S1 { }
    struct S2 { }
    
    let a = [S1(),S1()]
    // no dice - S2 is not a subtype of S1
    let b = a as? [S2]
    

    协议也无济于事:

    protocol P { }
    struct S1: P { }
    struct S2: P { }
    
    let a = [S1(),S1()]
    // still no good – just because S1 and S2 both conform to P
    // doesn’t mean S2 is a subtype of S1
    let b = a as? [S2]
    

    您的示例基本上是最后一个示例的变体。你有一个[T] 类型的数组,你想把它转换成[MyType]。重要的是要了解您没有[MyProtocol] 类型的数组。你的泛型类型T 是一个特定类型,它必须实现MyProtocol,但这不是一回事。

    要了解为什么不能从任何类型转换为任何其他类型,请尝试以下代码:

    protocol P { }
    struct S: P { }
    
    let a: [P] = [S(),S()]
    let b = a as? [S]
    

    这将产生一个运行时错误:“致命错误:不能在不同大小的类型之间使用 unsafeBitCast”。这暗示了为什么您只能将数组从包含一种引用类型转换为子类型——这是因为正在发生的事情只是从一种指针类型转换为另一种指针类型。这适用于超类/子类,但不适用于任意类、结构或协议,因为它们具有不同的二进制表示。

    【讨论】:

    • 再一次出色的解释。虽然这让我觉得泛型类型似乎不是一个好的语言概念,因为使用它们只需要一个蛋头。
    • 非常感谢您快速详细的回答。足以说服我不能这样做,但现在……我该怎么做?正是我想要的(实际上原始问题中的"Double!" 是它的踪迹)是一个具有泛型的类,它的泛型类型是Double 或Int。我想知道传递了什么类型并将其转换为正确的数组类型。我试图通过上面的方式做到这一点(结果证明这是不可能的,因为你教我。)你有什么想法吗?请原谅我的贪婪。
    • 也许我自己通过实现协议的一些功能解决了这个问题。谢谢。
    • @Akkyie 听起来你可能有一个使用associated values的枚举的用例
    【解决方案2】:

    子类型上的泛型不是父类型上相同泛型的子类型。

    [MyProtocol] 在 Swift 中实际上转换为 Array&lt;MyProtocol&gt;(即泛型)。 [MyType] 也是 Array&lt; MyType &gt; 的快捷方式。这就是为什么一个人不直接投射到另一个人。

    【讨论】:

    • 也感谢您的快速回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多