试图了解如何在内部处理 REPL 上声明的类 [英] Trying to understand how classes declared on the REPL are treated internally
问题描述
我试图了解 REPL 中的作用域是如何工作的.我尝试深入学习 Joshua Suereth 的书 Scala 的第 5.1.1 节.这是在 Windows XP、Java 7 和 Scala 2.9.1 上.我在 REPL 中声明了一个 Dinner
类.绑定 Dinner
存在于本地范围内.然后我实例化,因为它是本地绑定的.
I am trying to understand how scoping works in the REPL. I tried following Section 5.1.1 of Joshua Suereth's book Scala in depth.This is on Windows XP, Java 7 and Scala 2.9.1. I declare a class Dinner
in the REPL. The binding Dinner
exists in the local scope. Then I instantiate because it is locally bound.
scala> class Dinner {
| val veggie="broccoli"
| def announceDinner(veggie: String){
| println("Dinner happens to be tasteless " + veggie + " soup")
| }
| }
defined class Dinner
scala> new Dinner
res1: Dinner = Dinner@27fb77
到目前为止一切顺利.名称 Dinner
在本地绑定,我们还可以构造一个 val x
来保存对 new Dinner
的引用.
So far so good. The name Dinner
was bound locally and we could also construct a val x
that could hold a reference to new Dinner
.
据我目前所知,REPL 将在内部将上述代码包装在对象中.好吧,我对 Scala 的了解还不够深入,我正在尝试了解 REPL 如何在内部封装 Class.
From what I know so far, The REPL will wrap the above code in objects internally. Okay, my knowledge of Scala is not quite as deep yet and I am trying to understand how Class might be internally wrapped by the REPL.
是否有 REPL 命令可以帮助我评估这些对象?
Is there an REPL command that can help me evaluate these objects?
推荐答案
这里有一个非常快速和肮脏的方式来了解 REPL 中发生的事情.
Here goes a very quick and dirty way to what is going on in the REPL.
使用 scala -Xprint:typer 调用 REPL
Invoke the REPL with scala -Xprint:typer
scala> class Dinner {
| val veggie="broccoli"
| def announceDinner(veggie: String){
| println("Dinner happens to be tasteless " + veggie + " soup")
| }
| }
[[syntax trees at end of typer]]// Scala source: <console>
package $line1 {
final object $read extends java.lang.Object with ScalaObject {
def this(): object $line1.$read = {
$read.super.this();
()
};
final object $iw extends java.lang.Object with ScalaObject {
def this(): object $line1.$read.$iw = {
$iw.super.this();
()
};
final object $iw extends java.lang.Object with ScalaObject {
def this(): object $line1.$read.$iw.$iw = {
$iw.super.this();
()
};
class Dinner extends java.lang.Object with ScalaObject {
def this(): $line1.$read.$iw.$iw.Dinner = {
Dinner.super.this();
()
};
private[this] val veggie: java.lang.String = "broccoli";
<stable> <accessor> def veggie: java.lang.String = Dinner.this.veggie;
def announceDinner(veggie: String): Unit = scala.this.Predef.println("Dinner happens to be tasteless ".+(veggie).+(" soup"))
}
}
}
}
}
[[syntax trees at end of typer]]// Scala source: <console>
package $line1 {
final object $eval extends java.lang.Object with ScalaObject {
def this(): object $line1.$eval = {
$eval.super.this();
()
};
private[this] val $print: String = {
$read.$iw.$iw;
"defined class Dinner\012"
};
<stable> <accessor> def $print: String = $eval.this.$print
}
}
defined class Dinner
正如你在上面看到的,Dinner
最终被包裹在 $line1.$read.$iw.$iw
中.现在让我们看看接下来会发生什么:
As you can check above Dinner
ends up wrapped into $line1.$read.$iw.$iw
. Now let's see what happens next:
[[syntax trees at end of typer]]// Scala source: <console>
package $line2 {
final object $read extends java.lang.Object with ScalaObject {
def this(): object $line2.$read = {
$read.super.this();
()
};
final object $iw extends java.lang.Object with ScalaObject {
def this(): object $line2.$read.$iw = {
$iw.super.this();
()
};
import $line1.$read.$iw.$iw.Dinner;
final object $iw extends java.lang.Object with ScalaObject {
def this(): object $line2.$read.$iw.$iw = {
$iw.super.this();
()
};
private[this] val res0: $line1.$read.$iw.$iw.Dinner = new $line1.$read.$iw.$iw.Dinner();
<stable> <accessor> def res0: $line1.$read.$iw.$iw.Dinner = $iw.this.res0
}
}
}
}
[[syntax trees at end of typer]]// Scala source: <console>
package $line2 {
final object $eval extends java.lang.Object with ScalaObject {
def this(): object $line2.$eval = {
$eval.super.this();
()
};
lazy private[this] var $result: $line1.$read.$iw.$iw.Dinner = {
$eval.this.$print;
$line2.$read.$iw.$iw.res0
};
private[this] val $print: String = {
$read.$iw.$iw;
"res0: $line1.$read.$iw.$iw.Dinner = ".+(scala.runtime.ScalaRunTime.replStringOf($line2.$read.$iw.$iw.res0, 1000))
};
<stable> <accessor> def $print: String = $eval.this.$print
}
}
与之前基本相同,但使用 $line2
而不是 $line1
.请注意 $line2.$read.$iw.$iw
之前的 import $line1.$read.$iw.$iw.Dinner
.
Basically the same thing as before but using $line2
instead of $line1
. Notice the import $line1.$read.$iw.$iw.Dinner
right before $line2.$read.$iw.$iw
.
通过这种方式我们可以看到为什么在两个不同的行中定义伴生对象不起作用,它们最终被包装到不同的对象中,并且伴生需要在同一个范围/源文件中定义.
This way we can see why defining companion objects in two different lines doesn't work, they end up wrapped into different objects and companions need to be defined in the same scope/source file.
这篇关于试图了解如何在内部处理 REPL 上声明的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!