英文:
Why is this cast in my generic Kotlin function unchecked?
问题
把这个 MVCE 看一下:
abstract class Bar
class BarHolder(val barFunctor: Bar.() -> Unit)
fun <T : Bar> foo(bar: T.() -> Unit) {
val activeRequest = BarHolder(bar as (Bar.() -> Unit))
}
这里的强制类型转换 bar as (Bar.() -> Unit)
被标记为未检查。但是我想不出在运行时会出现强制转换失败的情况,因为 T
总是 Bar
的子类,对吗?
我知道可以通过添加 @Suppress("UNCHECKED_CAST")
来忽略它,但我认为这是不好的做法。那么避免不安全转换的正确方法是什么?
为了更多的上下文,预期的用例类似于这样:
class LongBar : Bar() {
val length = 69
}
fun foobar() {
foo<LongBar> {
println(length)
}
}
英文:
Take a look at this MVCE:
abstract class Bar
class BarHolder(val barFunctor : Bar.()-> Unit)
fun <T : Bar>foo(bar: T.() -> Unit) {
val activeRequest = BarHolder(bar as (Bar.() -> Unit))
}
The cast bar as (Bar.() -> Unit)
is marked as unchecked. But I can't think of a scenario where the cast fails at runtime, since T
is always a subclass of Bar
, isn't it?
I know I can ignore it by adding @Suppress("UNCHECKED_CAST")
but this seems bad practice to me. So what is the right way to avoid the unsafe cast?
For more context, the intended use case looks similar to this:
class LongBar : Bar()
val length = 69
fun foobar(){
foo<LongBar>(){
println(length)
}
}
答案1
得分: 4
你的代码不是类型安全的,而且 Kotlin 是正确的,不应该允许这样做。
问题在于你可能有一个特定类型的 Bar
的消费者,例如 Bar1
,然后将其转换为任何 Bar
对象的消费者。如果你然后使用这个 Bar1
的消费者并将一个 Bar2
对象传递给它会发生什么呢?
fun main() {
val bar1Consumer: Bar1.() -> Unit = { toString() }
val holder = foo(bar1Consumer)
holder.barFunctor.invoke(Bar2()) // ClassCastException
}
fun <T : Bar> foo(bar: T.() -> Unit) = BarHolder(bar as (Bar.() -> Unit))
class Bar1 : Bar()
class Bar2 : Bar()
很难与你的真实示例相关联,因为我们不知道 foo()
中到底发生了什么,但请注意,在进行了不受检查的强制类型转换之后,以下操作是允许的并将引发 ClassCastException
:
val activeRequest = BarHolder(bar as (Bar.() -> Unit))
activeRequest.barFunctor.invoke(IntBar())
英文:
Your code is not type-safe and Kotlin is correct it should not be allowed.
The problem is that you may have a consumer of a very specific type of Bar
, for example Bar1
and then you cast it to consumer of any Bar
objects. What if you then use this consumer of Bar1
and pass a Bar2
object to it?
fun main() {
val bar1Consumer: Bar1.() -> Unit = { toString() }
val holder = foo(bar1Consumer)
holder.barFunctor.invoke(Bar2()) // ClassCastException
}
fun <T : Bar>foo(bar: T.() -> Unit) = BarHolder(bar as (Bar.() -> Unit))
class Bar1 : Bar()
class Bar2 : Bar()
It is hard to relate to your real example as we don't know what exactly happens in foo()
, but please note after that unchecked cast this is allowed and will throw the ClassCastException
:
val activeRequest = BarHolder(bar as (Bar.() -> Unit))
activeRequest.barFunctor.invoke(IntBar())
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论