【问题标题】:Kotlin Smart Casting generic type by smartcasting argument通过 smartcasting 参数的 Kotlin Smart Casting 泛型类型
【发布时间】:2019-12-19 21:42:59
【问题描述】:

我正在尝试实现类似于以下玩具示例的内容:

fun getBoolean() = true
fun getFloat() = 1.0F
fun getInt() = 1
fun getLong() = 1L
fun getString() = "foobar"

fun <T> extract(defaultVal: T): T = when (defaultVal) {
    is Boolean -> getBoolean() as T
    is Float -> getFloat() as T
    is Int -> getInt() as T
    is Long -> getLong() as T
    is String -> getString() as T
    else -> defaultVal
}

在不同的情况下,有没有办法在没有未经检查的演员 as T 的情况下实现这一目标?

删除未经检查的强制转换会导致编译器错误,返回类型是函数的类型,而不是 T。我觉得编译器应该能够通过defaultVal is ____ 中的when 语句推断T,类似于智能转换:

fun usesInt(arg: Int) = arg + 1

fun <T> extract(defaultVal: T): T = when (defaultVal) {
    // ...
    is Int -> {
        usesInt(defaultVal)  // defaultVal is smart cast to Int => T is Int
        getInt() as T
    }
    // ...
}

这是智能投射/推理系统的缺点,还是我在这里遗漏了什么?

【问题讨论】:

    标签: kotlin casting


    【解决方案1】:

    首先,在投射时做出这样的假设是无效的。考虑一下:

    open class Base
    class Derived: Base()
    
    fun getBoolean() = true
    fun getBase() = Base()
    
    fun <T> extract(defaultVal: T): T = when (defaultVal) {
        is Boolean -> getBoolean() as T
        is Base -> getBase() as T
        else -> defaultVal
    }
    

    如果你这样做:

    val extracted: Derived = extract(Derived())
    

    您将收到 ClassCastException,因为它试图将 Base 转换为 Derived。

    我想他们可以让它更复杂,并检查这些类是否为open,但这会涉及很多逻辑。如果它在所有领域都如此复杂,我认为编译会超级慢。

    其次,转换为泛型类型总是会给您一个未经检查的转换警告,因为根本无法检查泛型类型。另一种方法是创建函数inline 和类型reified。那么它就不是未经检查的强制转换,但是如果你犯了上面的错误,你仍然会得到一个 ClassCastException。

    【讨论】:

    • 非常感谢,我只考虑原始类型(由于提出了用例)。如果假设原始类型存在一些泛型类型约束,您认为这在理论上是可能的吗,或者关于转换为泛型类型的相同规则是否适用?
    • 您是在问智能投射是否可行?在我看来,现在不仅适用于原语,而且适用于任何最终类,只是可能比实际更复杂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 2018-07-26
    相关资源
    最近更新 更多