我正在学习Scala,我不太了解以下示例:
object Test extends App {
def method1 = println("method 1")
val x = {
def method2 = "method 2" // method inside a block
"this is " + method2
}
method1 // statement inside an object
println(x) // same
}
我的意思是,感觉与我不一致,因为在这里我看到了两个不同的概念:
但是这里我们有一个块的方法部分,并且声明了对象的一部分。那么,它是否意味着块也是对象?如何处理对象的语句部分,它们也是成员吗?
感谢。
答案 0 :(得分:2)
这是否意味着块也是对象?
不,块不是对象。块用于确定变量的绑定范围。 Scala不仅可以在块内定义表达式,还可以定义方法。如果我们拿你的例子并编译它,我们可以看到编译器的作用:
object Test extends Object {
def method1(): Unit = scala.Predef.println("method 1");
private[this] val x: String = _;
<stable> <accessor> def x(): String = Test.this.x;
final <static> private[this] def method2$1(): String = "method 2";
def <init>(): tests.Test.type = {
Test.super.<init>();
Test.this.x = {
"this is ".+(Test.this.method2$1())
};
Test.this.method1();
scala.Predef.println(Test.this.x());
()
}
}
编译器所做的是将method2
提取到method2$1
上的“未命名”方法,并将其范围限定为private[this]
,其范围限定为当前该类型的实例。
如何处理对象的语句部分,是否为成员 太?
编译器使用method1
和println
并在初始化类型时在构造函数内调用它们。所以你可以看到val x
,并且在构造时调用其余的方法调用。
答案 1 :(得分:1)
method2
实际上不是一种方法。这是一个本地功能。 Scala允许您在本地范围内创建命名函数,以便将代码组织到函数中,而不会污染命名空间。
它最常用于定义本地尾递归辅助函数。通常,在使函数尾递归时,需要添加一个额外的参数来在调用堆栈上传递“状态”,但是这个附加参数是私有的内部实现细节,不应该暴露给客户端。在没有本地函数的语言中,你可以将它作为主要方法的private
助手和,但它仍然在类的命名空间内,并且可以由类的所有其他方法调用,当它真的只对 特定方法有用。因此,在Scala中,您可以在方法中本地定义它:
// non tail-recursive
def length[A](ls: List[A]) = ls match {
case Nil => 0
case x :: xs => length(xs) + 1
}
//transformation to tail-recursive, Java-style:
def length[A](ls: List[A]) = lengthRec(ls, 0)
private def lengthRec[A](ls: List[A], len: Int) = ls match {
case Nil => len
case x :: xs => lengthRec(xs, len + 1)
}
//tail-recursive, Scala-style:
def length[A](ls: List[A]) = {
//note: lengthRec is nested and thus can access `ls`, there is no need to pass it
def lengthRec(len: Int) = ls match {
case Nil => len
case x :: xs => lengthRec(xs, len + 1)
}
lengthRec(ls, 0)
}
现在你可能会说,我看到了在方法中定义局部函数的价值,但是能够在块中定义局部函数的价值是什么? Scala尝试尽可能简单并且尽可能少地使用极端情况。如果你可以在方法中定义局部函数,在局部函数中定义局部函数......那么为什么不简化那个规则,只是说局部函数的行为就像本地字段一样,你只需在任何块范围内定义它们即可。 。那么您不需要为本地字段和本地函数使用不同的范围规则,并且您已经简化了语言。
你提到的另一件事是,能够在模板的bode中执行代码,这实际上是主要的构造函数(可以这么说......它在技术上更像是初始化程序)。请记住:主要构造函数的签名是在类名后面用括号定义的......但是在哪里可以为构造函数放置代码呢?好吧,你把它放在课堂上!