是否有(优雅)方式转换为仅在运行时可用的类型?请检查一下:
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
的type参数在运行时都不知道。
没有完美的方法来解决此问题,因为使用这样的泛型本质上是不安全的。可能有一种重新考虑您的解决方案的方法来避免这种情况的发生(通常,将星形投影类型的值突变是一个坏主意,这就是为什么类型系统阻止您将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)
}
我认为这可能是解决此问题的最优雅的方法。