2012-02-22 4 views
3

Первый. Рассмотрим следующий код:Почему scalac генерирует дополнительные/упаковочные затворы

scala> val fail = (x: Any) => { throw new RuntimeException } 
fail: Any => Nothing = <function1> 

scala> List(1).foreach(fail) 
java.lang.RuntimeException 
    at $anonfun$1.apply(<console>:7) 
    at $anonfun$1.apply(<console>:7) 
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59) 

Существует дополнительный анонс между foreach и исключением. Ожидается, что одно из значений будет иметь значение fail (объект класса Function1 []), но откуда берется второе?

foreach подпись берет эту функцию:

def foreach[U](f: A => U): Unit 

Итак, какова цель второго?

Во-вторых, рассмотрим следующий код:

scala> def outer() { 
    | def innerFail(x: Any) = { throw new RuntimeException("inner fail") } 
    | 
    | Set(1) foreach innerFail 
    | } 
outer:()Unit 

scala> outer() 
java.lang.RuntimeException: inner fail 
    at .innerFail$1(<console>:8) 
    at $anonfun$outer$1.apply(<console>:10) 
    at $anonfun$outer$1.apply(<console>:10) 
    at scala.collection.immutable.Set$Set1.foreach(Set.scala:86) 

Есть два дополнительных anonfuns ... действительно ли они нужны? : -E

+0

Версия Scala 2.9.2.rdev-2769-2011-12-13-g2dd83da (виртуальная машина Java HotSpot TM TM, Java 1.6.0_25). – tuxSlayer

ответ

4

Давайте посмотрим на байт-код.

object ExtraClosure { 
    val fail = (x: Any) => { throw new RuntimeException } 
    List(1).foreach(fail) 
} 

Мы находим, внутри (одного) анонимной функции:

public final scala.runtime.Nothing$ apply(java.lang.Object); 
    Code: 
    0: new #15; //class java/lang/RuntimeException 
    3: dup 
    4: invokespecial #19; //Method java/lang/RuntimeException."<init>":()V 
    7: athrow 

public final java.lang.Object apply(java.lang.Object); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: invokevirtual #27; //Method apply:(Ljava/lang/Object;)Lscala/runtime/Nothing$; 
    5: athrow 

Так что это на самом деле не дополнительное закрытие в конце концов. У нас есть один метод, перегруженный двумя разными значениями возврата (что вполне нормально для JVM, поскольку он рассматривает тип всех параметров как часть сигнатуры функции). Функция является общей, поэтому она должна возвращать объект, но код, который вы написали, возвращает конкретно Nothing, он также создает метод, который возвращает тип, который вы ожидаете.

Существует множество способов обойти это, но ни один из них не имеет их недостатков. Это тот тип вещей, в котором JVM довольно хорошо справляются с этим, поэтому я не стал бы слишком беспокоиться об этом.

Редактирование: И, конечно, в вашем втором примере вы использовали def, а anonfun - это класс, который обертывает это def в объекте функции. Это, конечно, необходимо, так как foreach занимает Function1. Вы должны создать это Function1 как-то.

+0

О, я вижу. Но не лучше ли использовать (f: A => Any) в качестве параметра 'foreach()', чтобы избежать такого генерации. – tuxSlayer

+0

@tuxSlayer - Это все равно этого не сделает. 'A => Any' стирается до' Object => Object', который уже используется. –

+0

А ... :) получите – tuxSlayer

Смежные вопросы