更明确地说,此代码可以在任何scenrios中产生任何错误:
def foreach[U](f :Int=>U) = f.asInstanceOf[Int=>Unit](1)
我知道它有效,而且我有一个模糊的想法:为任何函数,作为泛型类型的实例,必须定义apply
的擦除版本,并且jvm仅在对象实际上执行时执行类型检查返回到具有混凝土类型的代码(通常在数英里之外)。所以,从理论上讲,只要我从不查看返回值,我就应该是安全的。我对Java字节代码没有足够的低级理解,更不用说scalac
,对它有任何确定性。
我为什么要这样做?请看以下示例:
val b = new mutable.Buffer[Int]
val ints = Seq(1, 2, 3, 4)
ints foreach { b += _ }
这是典型的scala结构,只要命令式风格可以是典型的。此示例中的foreach
将Int
作为参数,并且scalac知道它是Int
,它将创建一个具有专门apply(x :Int)
的闭包。不幸的是,在这种情况下,它的返回类型是mutable.Buffer[Int]
,它是AnyRef
。据我所知,如果结果为scalac
,apply
将永远不会调用提供AnyVal
参数的专用AnyRef
(反之亦然)。这意味着,即使调用者将函数应用于Int
,函数下方也会对参数进行装箱并调用已擦除的变量。这当然无关紧要,因为无论如何它们都在List
内,但我正在谈论这个原则。
出于这个原因,我更喜欢将此类方法定义为foreach(f :X=>Unit)
,而不是foreach[O](f: X=>O)
中的TraversableOnce
。如果示例中的输入序列具有这样的签名,则所有内容都将编译得很好,编译器将忽略表达式的实际类型并生成具有Unit
返回类型的函数,该函数应用于未装箱时Int
- 直接调用void apply(Int x)
,无需拳击。
问题出现在互操作性上 - 有时我需要调用一个期望具有Unit
返回类型的函数的方法,而我所拥有的只是一个泛型函数,返回Odin知道什么。当然,我可以写f(_)
将它放在另一个函数对象中而不是直接传递它,但它在很大程度上使得小紧环的整个优化没有实际意义。