我有一个像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
无效。
答案 0 :(得分:5)
Kotlin不支持交叉类型。这会导致variable
被智能转换为Any
,因为这是A
和B
的共同祖先。
但是,Kotlin确实支持泛型类型约束。您可以使用它将类型参数约束为一种或多种类型。这可以在方法和类上使用。这是函数的语法(相当于Kotlin中的methodName
):
fun <T> methodName(arg: T)
where T : A,
T : B {
....
}
您可以通过创建一个扩展A
和B
的类来解决您的问题,然后将这些类型的实现委托给您的对象。像这样:
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
类未实现hashCode
,equals
或toString
。您可以实施它们以委派给t
的实施。
注2:仅当A
和B
是接口时才有效。你不能委托给一个班级。
答案 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 交集类型的更多讨论和可运行示例