为什么允许将方法放在块中,并将语句放在Scala中的对象内?

时间:2017-04-09 02:53:40

标签: scala

我正在学习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
}

我的意思是,感觉与我不一致,因为在这里我看到了两个不同的概念:

  • 对象/类/特征,包含成员。
  • 块,包含语句,最后一个语句是块的值。

但是这里我们有一个块的方法部分,并且声明了对象的一部分。那么,它是否意味着块也是对象?如何处理对象的语句部分,它们也是成员吗?

感谢。

2 个答案:

答案 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],其范围限定为当前该类型的实例。

  

如何处理对象的语句部分,是否为成员   太?

编译器使用method1println并在初始化类型时在构造函数内调用它们。所以你可以看到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中执行代码,这实际上是主要的构造函数(可以这么说......它在技术上更像是初始化程序)。请记住:主要构造函数的签名是在类名后面用括号定义的......但是在哪里可以为构造函数放置代码呢?好吧,你把它放在课堂上!