如何转换为仅在运行时已知的类型
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)
}
我认为这可能是解决此问题的最优雅的方法。
是否有一种(优雅的)方法可以转换为仅在运行时可用的类型?请检查一下:
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)
}
我认为这可能是解决此问题的最优雅的方法。