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

问题描述 投票:0回答:2

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

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)
}

哦,无法分别为每种类型创建列表! ;-)

generics kotlin typing
2个回答
0
投票

由于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参数,并且不进行强制转换,但是您可能会冒险默默接受错误类型的值,只有在访问和使用该值时才会失败。


0
投票

为了避免在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)
}

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

© www.soinside.com 2019 - 2024. All rights reserved.