Swift 泛型数组错误

5

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

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不是'T'的子类型”。我认为,然而,MyTypeT是兼容的。

当我修改了if let语句后,它就可以正常工作了:

if let first = array.first as? MyType

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

我想知道问题出在哪里。我的理解有问题吗?或者是Swift语言的限制?如果是这样的话,有没有什么办法可以做到这一点?

提前感谢。

2个回答

4

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]

这将生成运行时错误:“fatal error: can't unsafeBitCast between types of different sizes”。这提示了为什么只能从包含一个引用类型的数组转换为子类型 - 因为所发生的只是从一种指针类型到另一种类型的位转换。 这对于超/子类型类可行,但对于任意类、结构体或协议则不行,因为它们具有不同的二进制表示。


1
再一次很好的解释。尽管它让我感到通用类型似乎不是一个好的语言概念,因为使用它们只需要一个蛋头。 - qwerty_so
非常感谢您快速而详细的回答。这已经足够让我相信我不能用这种方式做,但现在...我该怎么办呢?我想要的正是(实际上,“Double!”是它的痕迹),一个带有泛型的类,其泛型类型为Double或Int。我想知道传递的类型并将其强制转换为适当的数组类型。我尝试通过以上方式来实现这一点(正如您所教导的那样,这是不可能的)。您有任何想法吗?请原谅我的贪心。 - Akkyie
也许我通过实现一些协议函数自己解决了它。谢谢。 - Akkyie
@Akkyie,看起来你可能需要使用带有关联值的枚举类型。 - Airspeed Velocity

3

子类型上的泛型不能作为父类型上相同泛型的子类型。

在Swift中,[MyProtocol]实际上是Array<MyProtocol>(即一种泛型)。同样,[MyType]Array< MyType >的快捷方式。这就是为什么不能直接将一个类型转换为另一个类型的原因。


谢谢您的快速回答。 - Akkyie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接