在 kotlin 中,Optional.of 不能使用泛型参数

Vis*_*ium 3 kotlin

为什么这不能编译?

fun <T> returnOptionalOf(t: T): Optional<T> {
    val optional: Optional<T> = Optional.of(t)
    return optional
}
Run Code Online (Sandbox Code Playgroud)

错误是

类型不匹配:推断类型为 T,但预期为 T 和 Any

如何让它发挥作用?

这编译得很好:

fun returnOptionalOfString(t: String): Optional<String> {
    val optional: Optional<String> = Optional.of(t)
    return optional
}
Run Code Online (Sandbox Code Playgroud)

Jof*_*rey 5

我的第一个建议是避免Optional使用 Kotlin 中的类型。可空类型提供了关于值是否可以包含空值的相同编译时保证,它们强制您在正确的位置检查空值,并且它们更惯用(还有大量语法糖可以帮助处理可为空值,例如?:?.运算符)。

现在回到您的具体问题,您看到的是对您不利的几件事的组合:

  • 在你的函数签名中,你T根本没有约束。这意味着 可能T是可为 null 的类型(例如String?),这又意味着该函数接受 null。请注意,这Optional.of是一个需要非空值的 Java 函数,如果null作为参数给出,则会抛出 NPE。在这种情况下,您可能需要仔细检查抛出 NPE 是否是您的函数的预期目的。

  • 另一个(更大的)问题是,您可能假设 是Optional<T>协变的T,但它实际上是不变的(可能是因为它是一个 Java 类,并且没有做任何特殊处理,但有一个问题需要更改它)。更清楚地说,这意味着即使是 的Optional<A>子类型,也不是的子类型,因此不能为类型为 的变量赋值。Optional<B>ABOptional<String>Optional<String?>

  • 第三件事是Optional工厂函数of实际上ofNullable会返回您传递的类型的不可为空的投影,因此总是如此Optional<T & Any>(因为 null 值将分别失败或导致为空Optional)。例如,Optional.of<String?>("abc") 仍然返回一个,这与 中 不变的Optional<String>事实不能很好地配合。OptionalT

这解释了为什么变量的显式类型 ( Optional<T>)optional不正确。因为Optional.of返回 a Optional<T & Any>,它不能分配给类型的变量Optional<T>(即使T & Any是 的子类型T)。

这可能有很多行话,所以让我通过使用您的字符串示例来澄清,但不要使用StringasT让我们使用String?

fun returnOptionalOfString(t: String?): Optional<String?> {
    val optional: Optional<String?> = Optional.of(t) // error here
    return optional
}
Run Code Online (Sandbox Code Playgroud)

在这里,您将看到相同的作业错误,但用更简单的术语表示。

正如 @marstran 已经提到的,解决所有这些问题的一种方法是在处理Optionals 时仅使用不可为 null 的类型。在您的情况下,这意味着限制T使用: Any

fun <T : Any> returnOptionalOf(t: T): Optional<T> {
    val optional: Optional<T> = Optional.of(t)
    return optional
}
Run Code Online (Sandbox Code Playgroud)