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

Generics 如何强制转换为仅在运行时已知的类型,generics,kotlin,typing,Generics,Kotlin,Typing,是否有一种(优雅的)方法可以强制转换为仅在运行时可用的类型?请查看以下内容: 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, fa

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

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)
}
数据类Foo(
var值:T
)
val foos=listOf(
Foo(value=“I a字符串”),
Foo(值=1),
Foo(值=真)
)
val anyTypes=listOf(“字符串”,1,false)
主要内容(){
forEachIndexed(){idx,foo->
foo.value=anyTypes[idx]
}
foos.forEach(::println)
}
哦,而且不可能分别为每种类型创建列表!;-)

由于,每个
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)
数据类Foo(
val类型:KClass,
var值:T
)
val foos=listOf(
Foo(String::class,value=“I a String”),
Foo(Int::class,value=1),
Foo(布尔::类,值=true)
)
val anyTypes=listOf(“字符串”,1,false)
...
foos.foreachinedexed{idx,foo->
@抑制(“未选中的_CAST”)
(foo作为foo.value=foo.type.cast(anyTypes[idx])
}
foos.forEach(::println)
您也可以省略
KClass
参数而不执行强制转换,但这样做可能会导致默认接受错误类型的值,只有在访问和使用该值时才会失败。

由于,每个
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)
数据类Foo(
val类型:KClass,
var值:T
)
val foos=listOf(
Foo(String::class,value=“I a String”),
Foo(Int::class,value=1),
Foo(布尔::类,值=true)
)
val anyTypes=listOf(“字符串”,1,false)
...
foos.foreachinedexed{idx,foo->
@抑制(“未选中的_CAST”)
(foo作为foo.value=foo.type.cast(anyTypes[idx])
}
foos.forEach(::println)

您也可以省略
KClass
参数,不使用强制转换,但这样做可能会导致默认接受错误类型的值,这只会在访问和使用该值时失败。

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

数据类Foo(
var值:T
) {
@抑制(“未选中的_CAST”)
趣味tryCastAndSet(任意项:任意项){
值=作为T的任何值
}
}
val foos=listOf(
Foo(value=“I a字符串”),
Foo(值=1),
Foo(值=真)
)
val anys=listOf(“字符串”,1,false)
主要内容(){
foos.foreachinedexed{idx,foo->
foo.tryCastAndSet(anys[idx])
}
foos.forEach(::println)
}

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

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

数据类Foo(
var值:T
) {
@抑制(“未选中的_CAST”)
趣味tryCastAndSet(任意项:任意项){
值=作为T的任何值
}
}
val foos=listOf(
Foo(value=“I a字符串”),
Foo(值=1),
Foo(值=真)
)
val anys=listOf(“字符串”,1,false)
主要内容(){
foos.foreachinedexed{idx,foo->
foo.tryCastAndSet(anys[idx])
}
foos.forEach(::println)
}

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

为什么不
val foos=listOf
?为什么不
val foos=listOf
?这会编译,但强制转换实际上不会做任何事情,因此在插入错误类型的值时不会遇到任何错误。用不同类型的值替换
anys
中的任何值,您将注意到不会有任何更改;一旦该值被访问和使用,程序将立即启动,就像它是
T
一样。这会编译,但强制转换实际上不会执行任何操作,因此在插入错误类型的值时不会遇到任何错误。用不同类型的值替换
anys
中的任何值,您将注意到不会有任何更改;一旦访问并使用该值,程序将立即启动,就像它是
T
一样。