在Swift Generics中强制超类

时间:2014-06-20 13:44:13

标签: generics swift

我正在尝试实现一种新方法来加入两个Array,并将包含公共数据类型的Array返回给另外两个。

为了清楚说明,我希望有办法做一些事情(知道语法不正确......):

@infix func + <T,U,X where X super T, X super U>(left : Array<T>, right : Array<U>) 
-> Array<X>{
    //join both arrays
}

始终认为编译器能够检测两个类的共同祖先类型。如果这实际上是不可能的,那么正确的方法是什么?使那个“超级”类型明确吗?

2 个答案:

答案 0 :(得分:1)

斯威夫特的类型推断比你想象的要聪明。秘诀是查看nil-coalescing运算符??的签名:

func ??<T>(optional: T?, defaultValue: @autoclosure () -> T) -> T
func ??<T>(optional: T?, defaultValue: @autoclosure () -> T?) -> T?

使用此运算符时很明显,它会将T提升为传递给它的任何类型的最近共同祖先,一直到Any,例如:

let i: Int? = 3
let s: String? = "3"
let a: Any? = i ?? s

这会编译并运行,但a的类型是Any(实际上是一个协议)。在某些情况下,您需要向编译器提供类型证据,在某些情况下,您不需要。如果类型共享不是协议的共同祖先,则看起来不需要证据。您可能认为??正在由编译器进行特殊处理,但事实并非如此。你可以很容易地自己动手。

为了你的尝试,你正在过度思考它。 (就像我遇到类似问题时那样。)你只需要一个类型。

如果我们将+作为一个函数实现,它将如下所示:

func joinArrays<T>(array1: [T], array2: [T]) -> [T] {
    return array1 + array2
}

class Base {}
class Derived1 : Base {}
class Derived2 : Base {}

let a1 = [Derived1(), Derived1()]
let a2 = [Derived2(), Derived2()]
let a = joinArrays(a1, a2)

a的类型为Array<Base>,因为这是泛型类型参数的最近共同祖先。

我已经使用这种“类型促销”来创建各种复杂的合并/一元运算符,例如Haskell。唯一的问题是Swift不支持泛型类型参数的协方差。

答案 1 :(得分:0)

您可以使用:语法,如下所示:

// The parameter must be a UIViewController, or subclass
func changeViewColor<T: UIViewController>(vc: T) {
    vc.view.backgroundColor = UIColor.redColor()
}