在Swift中检查泛型子类

时间:2018-12-31 08:37:15

标签: swift generics

我迅速具有以下功能:

func test<C1,C2>(val1: C1, val2: C2) {
}

但是我想使用where来约束此功能,直到C2C1的子类时。我尝试过这样的事情:

func test<C1,C2>(val1: C1, val2: C2) where C2: C1 {
}

但是它不起作用,并显示错误Type 'C2' constraint to non-protocol, non-class type 'C1'。知道我应该怎么做吗?

1 个答案:

答案 0 :(得分:0)

有什么问题?

: 表示 type constraint

<块引用>

类型约束指定类型参数必须从特定的类继承,或者符合特定的协议或协议组合。

不幸的是,这仅允许指定符合已知类或协议,而不能符合其他泛型类型的类型。

例如:

class C {}
func test1<C1,C2:C1>(val1: C1, val2: C2) {  // Not valid C1 is a generic
}
func test2<C1,C2:C>(val1: C1, val2: C2) {   // Valid since C is a known type
}

这同样适用于进一步约束类型或关联类型的 where 子句。

func test3<C1,C2>(val1: C1, val2: C2) where C2:C1 {  // Not valid C1 is a generic
}
func test4<C1,C2>(val1: C1, val2: C2) where C2:C {   // Valid since C is a known type
}

where 子句可以是关于 : 的类型一致性,也可以是关于与 == 的已知类型具有相同的类型。

为什么会有这样的限制

当已知类型起作用时,语言设计允许您有专门的实现:

func test5<C1,C2>(_ val1: C1, _ val2: C2) {   
    print ("general test5")
}
func test5<C1,C2:C>(_ val1: C1, _ val2: C2) {  
    print ("special case of test5") 
}
let p1="Hello world!"
let p2=12
class MyClass:C {}
let p3 = MyClass()
test5(p1,p2)    // ---> general test5
test5(p1,p3)    // ---> special case of test5

但是此功能对已知类型的限制阻止了定义专门的实现,以防一种类型是另一种类型的子类型。

这可能是有充分理由的。如果允许符合泛型类型,则可能有不止一种合适的特化,编译器将没有任何规则可供选择。假设示例,将具有泛型一致性的 与另一个泛型相加:

func test5<C1,C2>(_ val1: C1, _ val2: C2) where C2:C1 {   
    print ("super special case of test5") 
}

在这个假设的例子中,编译器不知道选择哪个特化test5(p1,p3)

解决方法

但是,您可以实现两种类型的函数并在函数体中处理特殊的一致性情况:

func test<C1,C2>(_ object1: C1, _ object2: C2){
    let concreteType1 = type(of: object1)
    let concreteType2 = type(of: object2)
    if object2 is T {  // check if C2 conforms to C1
        print ("\(concreteType2) conforms to \(concreteType1)")
    }
    else {
        print ("\(concreteType2) is incompatible with \(concreteType1)")
    }
}

请注意,根据您要执行的操作,您还可以考虑 as? 强制转换:

    if let object3 : C1 = object2 as? C1 {  // check if C2 is castable to C1
        let concreteType3 = type(of: object3)
        print (concreteType1, concreteType2, concreteType3)
    }