在Scala reduceLeft实现中的0.asInstanceOf [B]发生了什么
以下是Scala的
TraversableOnce特征的reduceLeft方法的来源。读取var acc:B = 0.asInstanceOf [B]的行发生了什么?
对我来说,如果我将这个字符串列在列表(“a”,“b”,“c”)这样的列表中,那么会导致类似于0.asInstanceOf [String]的内容。但是,如果我直接尝试,在运行时,0.asInstanceOf [String]会抛出ClassCastException。 该行发生了什么,为什么不同于在Strings列表上调用时直接调用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对象中的第一个元素覆盖该值。 解决方法
那么在运行时没有发生ClassCastException的原因是因为:
>编译器删除它从未使用的初始化推理(我怀疑这一点) 您可以通过检查字节码来测试第一种可能性,但它似乎是一个无意义的代码段。如果没有消除这种情况,那么每次调用该方法时都会有一个不必要的开销来控制Int(尽管不是一个对象创建 – 见下文)! 了解编译器生成的内容:1 Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM,Java 1.6.0_29). Type in expressions to have them evaluated. Type :help for more information. scala> trait X[A] { | def foreach[U](f: A => U): U | def isEmpty = { | var b = false | foreach(_ => b = true) | !b | } | def reduceLeft[B >: A](op: (B,A) => B): B = { | if (isEmpty) sys.error("Bad") | var first = true | var acc: B = 0.asInstanceOf[B] | for (x <- this) { | if (first) { acc = x; first = false } else acc = op(acc,x) | } | acc | } | } defined trait X 那么现在 scala> :javap -v X Compiled from "<console>" public interface X extends scala.ScalaObject SourceFile: "<console>" Scala: length = 0x Signature: length = 0x2 00 0D InnerClass: public abstract #19= #16 of #18; //X=class X of class public final #21; //class X$$anonfun$isEmpty$1 public final #23; //class X$$anonfun$reduceLeft$1 minor version: 0 major version: 49 Constant pool: const #1 = Asciz SourceFile; const #2 = Asciz <console>; const #3 = Asciz foreach; const #4 = Asciz (Lscala/Function1;)Ljava/lang/Object;; const #5 = Asciz <U:Ljava/lang/Object;>(Lscala/Function1<TA;TU;>;)TU;; const #6 = Asciz Signature; const #7 = Asciz isEmpty; const #8 = Asciz ()Z; const #9 = Asciz reduceLeft; const #10 = Asciz (Lscala/Function2;)Ljava/lang/Object;; const #11 = Asciz <B:Ljava/lang/Object;>(Lscala/Function2<TB;TA;TB;>;)TB;; const #12 = Asciz Scala; const #13 = Asciz <A:Ljava/lang/Object;>Ljava/lang/Object;Lscala/ScalaObject;; const #14 = Asciz InnerClasses; const #15 = Asciz X; const #16 = class #15; // X const #17 = Asciz ; const #18 = class #17; // const #19 = Asciz X; const #20 = Asciz X$$anonfun$isEmpty$1; const #21 = class #20; // X$$anonfun$isEmpty$1 const #22 = Asciz X$$anonfun$reduceLeft$1; const #23 = class #22; // X$$anonfun$reduceLeft$1 const #24 = Asciz java/lang/Object; const #25 = class #24; // java/lang/Object const #26 = Asciz scala/ScalaObject; const #27 = class #26; // scala/ScalaObject { public abstract java.lang.Object foreach(scala.Function1); Signature: length = 0x2 00 05 public abstract boolean isEmpty(); public abstract java.lang.Object reduceLeft(scala.Function2); Signature: length = 0x2 00 0B } 做那个你会的! 了解编译器生成的内容:2 另一种可能性是把它放在一个源文件和compile it,printing out the intermediate code phase: ./scalac -Xprint:icode X.scala 那你得到… def reduceLeft($this: X,op$1: Function2): java.lang.Object = { if ($this.isEmpty()) scala.sys.`package`.error("Bad") else (); var first$1: scala.runtime.BooleanRef = new scala.runtime.BooleanRef(true); var acc$1: scala.runtime.ObjectRef = new scala.runtime.ObjectRef(scala.Int.box(0)); $this.foreach({ (new anonymous class X$$anonfun$reduceLeft$1($this,op$1,first$1,acc$1): Function1) }); acc.elem }; 看起来很像是不必要的拳击在那里!一点是,这不会涉及对象创建,只是查找,因为-127到127的boxed值被缓存。 您可以通过将上述打印命令中的编译器阶段更改为“擦除”来检查已擦除的行。嘿presto: var acc: java.lang.Object = scala.Int.box(0).$asInstanceOf[java.lang.Object](); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |