在Kotlin可以进行交叉铸造吗?

时间:2017-06-09 03:06:06

标签: casting kotlin type-inference

我有一个像Java这样的方法:

public <T extends A & B> methodName(T arg, ...)

其中A是类,B是接口。

在我的kotlin课程中,我有另一个类型为C的variable,我希望实现以下目标:

if (variable is A && variable is B) {
    methodName(variable, ...)
} else {
    // do something else
}

是否可以正确转换variable以便可以将其用作参数而不会出错?

  

目前,variable有一个setter方法,所以智能转换不是   可用。但是,我还使用本地val测试了它   值被推断为类型Any无效。

2 个答案:

答案 0 :(得分:5)

Kotlin不支持交叉类型。这会导致variable被智能转换为Any,因为这是AB的共同祖先。

但是,Kotlin确实支持泛型类型约束。您可以使用它将类型参数约束为一种或多种类型。这可以在方法和类上使用。这是函数的语法(相当于Kotlin中的methodName):

fun <T> methodName(arg: T)
    where T : A,
          T : B {
    ....
}

您可以通过创建一个扩展AB的类来解决您的问题,然后将这些类型的实现委托给您的对象。像这样:

class AandB<T>(val t: T) : A by t, B by t
    where T : A,
          T : B

您现在可以通过更改if-test来调用methodName,以检查它是否为AandB<*>

if (variable is AandB<*>) {
    methodName(variable, ...)
}

您确实需要将variable包裹在AandB的某处。如果您在任何地方都没有variable的类型信息,我认为您无法做到。

注意:AandB类未实现hashCodeequalstoString。您可以实施它们以委派给t的实施。

注2:仅当AB是接口时才有效。你不能委托给一个班级。

答案 1 :(得分:0)

正如@marstran 指出的那样,when 子句是您指定多个边界的方式。这是有关 upper-bounds 的文档的链接。值得一提的是,如果您的一个边界是泛型类型参数,则您不能有多个边界。

您提到您尝试使用智能投射进行测试:

<块引用>

但是,我还使用本地 val 对其进行了测试,推断出该值的类型为 Any ,但没有帮助。

当前版本的 Kotlin (v1.4) 并非如此。您不需要需要创建一个 AandB 类,因为您可以使用 val 或本地(捕获的)var 智能投射到一个交叉路口。 >

这是一个示例(和 runnable version):

interface I1 { fun one() = println("one") }
interface I2 { fun two() = println("two") }
class Both: I1, I2

val variable: Any = Both() // Starting with type 'Any'

if (variable is I1 && variable is I2) {
    // Type is now '(I1 & I2)' Smart-cast from Any
    variable.one()
    variable.two()
}

这是一个 link 到 v1.4 的 Kotlin 交集类型的更多讨论和可运行示例