scala 了解为什么内联函数在收集时修复运行时崩溃

6jjcrrmo  于 2022-12-23  发布在  Scala
关注(0)|答案(1)|浏览(182)

我想了解为什么内联函数可以修复运行时错误。
下面的代码会导致运行时错误(参见下文)

[error] java.lang.ClassCastException: class Herbivore cannot be cast to class Food (Herbivore and Food are in unnamed module of loader sbt.internal.LayeredClassLoader @4837dd91)
trait GameObject
case class Food(x: Int) extends GameObject
case class Herbivore() extends GameObject

@main 
def main: Unit = 
    val xs = Vector(Food(1), Herbivore(), Food(2))
    
    def minBy[T <: GameObject](f: T => Double): Option[T] =
        xs.collect{case v: T => v}.minByOption(f)
    val done = minBy[Food](food => food.x)
    println(done)

直到我更改它,使minBy内联并按预期工作(输出:Some(Food(1)))。

inline def minBy[T <: GameObject](f: T => Double): Option[T] = //-snip-

这是故意的行为吗?

sz81bmfz

sz81bmfz1#

键入擦除。
当JVM看到这段代码时,它只能看到Vector[GameObject] .泛型参数的类型测试,嗯,它不能完成,因为这个参数在运行时没有传递到方法中,所以这个检查总是成功的。

def minBy(f: GameObject => Double): Option[GameObject] =
  xs.collect{case v => v} // collects everything
    .minByOption(f) // will run f against all values of xs

由于xs的所有值都将被传递到minByOption中的f中,并且您在那里不仅有Food,因此它将需要意外的类型。
在Scala 2中,您可以使用ClassTag添加运行时测试,但我看到您使用的是Scala 3,它具有TypeTest,在您的情况下,它应该使用其别名Typeable

import scala.reflect.Typeable
def minBy[T <: GameObject: Typeable](f: T => Double): Option[T] =
  xs.collect{case v: T => v}.minByOption(f)

它的行为应该像您手动编写的一样:

def minBy[T <: GameObject](f: T => Double)(using tt: Typeable[T]): Option[T] =
   xs.collect{ case tt(v) => v } // tt is providing unapply (extractor)
     .minByOption(f)

相关问题