如何转换为仅在运行时已知的类型

How to cast to a type that is only known at runtime

是否有一种(优雅的)方法可以转换为仅在运行时可用的类型?请检查一下:

data class Foo<T> (
    var value: T
)

val foos = listOf<Foo<*>>(
    Foo(value = "I a a String"),
    Foo(value = 1),
    Foo(value = true)
)

val anyTypes = listOf<Any>("String", 1, false)

fun main() {

    foos.forEachIndexed() { idx, foo ->
       foo.value = anyTypes[idx]
    }

    foos.forEach(::println)
}

哦,不可能为每种类型单独创建一个列表! ;-)

感谢 erasure,每个 Foo 的类型参数在运行时根本不知道。

没有完美的方法来解决这个问题,因为像这样使用泛型本质上是不安全的。可能有一种方法可以重新考虑您的解决方案以完全避免这种情况(改变星形投影类型的值通常是一个坏主意,这就是为什么类型系统阻止您将 null 以外的任何东西分配给上限不变类型的值.)

您必须提供类型本身作为每个 Foo:

的参数
data class Foo<T : Any> (
    val type: KClass<T>,
    var value: T
)

val foos = listOf<Foo<*>>(
    Foo(String::class, value = "I a a String"),
    Foo(Int::class, value = 1),
    Foo(Boolean::class, value = true)
)

val anyTypes = listOf<Any>("String", 1, false)

...
foos.forEachIndexed { idx, foo ->
    @Suppress("UNCHECKED_CAST")
    (foo as Foo<Any>).value = foo.type.cast(anyTypes[idx])
}

foos.forEach(::println)

您也可以省略 KClass 参数并且不进行强制转换,但是您可能会默默地接受错误类型的值,只有在访问和使用该值时才会失败。

为了避免将 Foo 中的值类型作为附加参数进行管理,我通过让 foo 自己处理 Foo.value 的转换和设置来解决这个问题。像这样:

data class Foo<T> (
    var value: T
) {
    @Suppress("UNCHECKED_CAST")
    fun tryCastAndSet(anything: Any) {
        value = anything as T
    }
}

val foos = listOf<Foo<*>>(
    Foo(value = "I a a String"),
    Foo(value = 1),
    Foo(value = true)
)

val anys = listOf<Any>("String", 1, false)

fun main() {

    foos.forEachIndexed { idx, foo ->
       foo.tryCastAndSet(anys[idx])
    }

    foos.forEach(::println)
}

我认为这可能是解决此问题的最优雅的方法。