下面是Scala的TraversableOnce trait的reduceLeft方法的来源 . 读取 var acc: B = 0.asInstanceOf[B]
的行发生了什么?
对我来说,似乎如果我在一个字符串列表上调用它,例如 List("a", "b", "c")
,这将导致像 0.asInstanceOf[String]
这样的东西 . 但是,如果直接尝试, 0.asInstanceOf[String]
会在运行时抛出 ClassCastException
.
该行发生了什么,为什么它与在字符串列表中调用时直接调用 0.asInstanceOf[String]
不同?
def reduceLeft[B >: A](op: (B, A) => B): B = {
if (isEmpty)
throw new UnsupportedOperationException("empty.reduceLeft")
var first = true
var acc: B = 0.asInstanceOf[B]
for (x <- self) {
if (first) {
acc = x
first = false
}
else acc = op(acc, x)
}
acc
}
奖金问题:为什么 acc
甚至被初始化为该值?看起来 for
循环的第一次迭代中的代码将使用 TraversableOnce
对象中的第一个元素覆盖该值 .
2 回答
好吧,这在运行时没有失败
ClassCastException
的原因是因为:编译器删除了从未使用过的初始化推理(我对此表示怀疑)
B是erased到
Object
(或AnyRef
),因此演员阵容真的0.asInstanceOf[Object]
您可以通过检查字节码来测试第一种可能性,但它似乎是一个毫无意义的代码 . 如果它没有被省略,那么每次调用该方法时都会产生不必要的开销
Int
(尽管不是对象创建 - 见下文)!弄清楚编译器产生的内容:1
所以现在:
做你想做的!
弄清楚编译器产生的内容:2
另一种可能性是将它放在源文件和_764969中:
然后你得到......
它看起来非常像在那里不必要的拳击!一点是,这不会涉及对象创建,只是查找,因为缓存了-127到127的装箱值 .
您可以通过将上述打印命令中的编译器阶段更改为“擦除”来检查已擦除的行 . 嘿presto:
可以通过尝试提出替代方案来推断奖金问题的答案 . 累加器是B型 . 你会分配给它什么B? (有一个更好的答案,即null.asInstanceOf [B]这是通常做的,但我认为这会留下你的问题 . )