Scalaではメソッドの中にネストしてメソッドが定義できますよね。
末尾再帰関数を書く時とかに使うことが多いと思いますが、一見「メソッドが呼ばれるたびに無名関数が生成されてコスト大きいのでは...」という感じもします。
その心配はないので、メソッドをネストさせないで引数を取り回すことで可読性が悪くなってる場合、ネストさせてすっきりさせていきましょう、という話です。
環境
- Scala 2.11.7
検証
以下のようなコードを用意します。
Foo.scala
package com.example
class Foo {
def top(i: Int): Unit = {
def nested(j: Int): Int = i + j
println(nested(1))
}
}
これをprintオプションつきでコンパイルすると
$ scalac -print Foo.scala
[[syntax trees at end of cleanup]] // Foo.scala
package com.example {
class Foo extends Object {
def top(i: Int): Unit = scala.this.Predef.println(scala.Int.box(Foo.this.nested$1(1, i)));
final private[this] def nested$1(j: Int, i$1: Int): Int = i$1.+(j);
def <init>(): com.example.Foo = {
Foo.super.<init>();
()
}
}
}
ネストしたメソッドはトップレベルに移動してることがわかります。
scalacにはlambdalift
というフェーズがあるので、そこで行われるようですね
$ scalac -Xshow-phases
phase name id description
...
lambdalift 17 move nested functions to top level
...
$ scalac -Xprint:lambdalift Foo.scala
[[syntax trees at end of lambdalift]] // Foo.scala
package com.example {
class Foo extends Object {
def <init>(): com.example.Foo = {
Foo.super.<init>();
()
};
def top(i: Int): Unit = scala.this.Predef.println(scala.Int.box(Foo.this.nested$1(1, i)));
final private[this] def nested$1(j: Int, i$1: Int): Int = i$1.+(j)
}
}