在 Kotlin 中可以进行相交铸造吗?
Is intersection casting possible in Kotlin?
我在 Java 中有一个方法,如下所示:
public <T extends A & B> methodName(T arg, ...)
其中 A 是一个 class,B 是一个接口。
在我的 kotlin class 中,我有另一个 variable
类型的 C,我希望实现以下目标:
if (variable is A && variable is B) {
methodName(variable, ...)
} else {
// do something else
}
是否可以正确转换 variable
以便它可以用作参数而不会出错?
Currently, the variable
has a setter method, so smart casting isn't
available. However, I have also tested it with a local val
and the
value is inferred to have type Any
which doesn't help.
Kotlin 不支持交集类型。这导致 variable
被智能转换为 Any
,因为那是 A
和 B
的共同祖先。
但是,Kotlin 确实支持泛型类型约束。您可以使用它来将类型参数限制为一种或多种类型。这可以用于方法和 classes。这是函数的语法(相当于 Kotlin 中的 methodName
):
fun <T> methodName(arg: T)
where T : A,
T : B {
....
}
您可以通过创建扩展 A
和 B
的 class 来解决您的问题,然后将这些类型的实现委托给您的对象。像这样:
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
class 未实现 hashCode
、equals
或 toString
。您可以实现它们以委托给 t
的实现。
注意 2:这仅在 A
和 B
是接口时有效。您不能委托给 class.
正如@marstran 指出的那样,when 子句是您指定多个边界的方式。这是关于 upper-bounds 的文档的 link。值得一提的是,如果您的边界之一是泛型类型参数,则您不能有多个边界。
您提到您尝试使用智能投射进行测试:
However, I have also tested it with a local val and the value is inferred to have type Any which doesn't help.
当前版本的 Kotlin (v1.4) 不是这种情况。您 不需要 创建一个 AandB
class,因为您可以使用 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 交集类型进行更多讨论和可运行的示例
我在 Java 中有一个方法,如下所示:
public <T extends A & B> methodName(T arg, ...)
其中 A 是一个 class,B 是一个接口。
在我的 kotlin class 中,我有另一个 variable
类型的 C,我希望实现以下目标:
if (variable is A && variable is B) {
methodName(variable, ...)
} else {
// do something else
}
是否可以正确转换 variable
以便它可以用作参数而不会出错?
Currently, the
variable
has a setter method, so smart casting isn't available. However, I have also tested it with a localval
and the value is inferred to have typeAny
which doesn't help.
Kotlin 不支持交集类型。这导致 variable
被智能转换为 Any
,因为那是 A
和 B
的共同祖先。
但是,Kotlin 确实支持泛型类型约束。您可以使用它来将类型参数限制为一种或多种类型。这可以用于方法和 classes。这是函数的语法(相当于 Kotlin 中的 methodName
):
fun <T> methodName(arg: T)
where T : A,
T : B {
....
}
您可以通过创建扩展 A
和 B
的 class 来解决您的问题,然后将这些类型的实现委托给您的对象。像这样:
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
class 未实现 hashCode
、equals
或 toString
。您可以实现它们以委托给 t
的实现。
注意 2:这仅在 A
和 B
是接口时有效。您不能委托给 class.
正如@marstran 指出的那样,when 子句是您指定多个边界的方式。这是关于 upper-bounds 的文档的 link。值得一提的是,如果您的边界之一是泛型类型参数,则您不能有多个边界。
您提到您尝试使用智能投射进行测试:
However, I have also tested it with a local val and the value is inferred to have type Any which doesn't help.
当前版本的 Kotlin (v1.4) 不是这种情况。您 不需要 创建一个 AandB
class,因为您可以使用 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 交集类型进行更多讨论和可运行的示例