繁体   English   中英

在斯卡拉;我应该使用App特质吗?

[英]In Scala; should I use the App trait?

我刚刚开始学习Scala,我正在遵循的许多教程都使用了一种main方法的不同表示形式的组合。 除了熟悉的主要方法; 还有使用特征AppApplication 看来Application已被弃用,不推荐使用,但我找不到任何有关这些定义入口点的方法的信息。

所以,我想知道是否有人可以向我解释:

  • AppApplication的特性如何工作?
  • 为什么不再推荐特质ApplicationApp特性有何不同?
  • 我应该在哪里使用传统的主要方法,何时应该使用App来启动我的程序? 这两种方法有什么区别?

Application trait的问题实际上在其文档中描述:

(1)引用该对象的线程代码将阻塞,直到静态初始化完成。 但是,因为扩展Application的对象的整个执行发生在静态初始化期间,所以如果并发代码必须与封闭对象同步,则它们将始终死锁。

这是一个棘手的问题。 如果扩展Application特征,则基本上是创建Java类:

class MyApplication implements Application {
  static {
    // All code goes in here
  }
}

JVM运行在MyApplication类上隐式同步的上述类初始化程序。 这样,可以确保在初始化类之前不会创建MyApplication实例。 如果从应用程序生成一个再次需要访问MyApplication实例的线程,则应用程序将无法锁定,因为类初始化仅在整个程序执行完毕后才完成。 这意味着一个矛盾,因为只要您的程序正在运行,就不能创建任何实例。

(2)如上所述,无法获取命令行参数,因为扩展Application的对象体中的所有代码都是作为静态初始化的一部分运行的,这是在Application的main方法甚至开始执行之前发生的。

类初始值设定项不接受任何参数。 此外,它首先运行,然后可以将任何值传递给类,因为在您甚至可以分配静态字段值之前需要执行类初始化程序。 因此,您通常在main方法上收到的args会丢失。

(3)静态初始化程序在程序执行期间只运行一次,而JVM作者通常认为它们的执行时间相对较短。 因此,某些JVM配置可能会变得混乱,或者只是无法优化或JIT扩展Application的对象体中的代码。 这可能导致显着的性能下降。

JVM优化了经常运行的代码。 这样,它确保不会浪费任何不是性能瓶颈的方法的运行时间。 但是,它安全地假定static方法只执行一次,因为它们无法手动调用。 因此,它不会优化从类初始化程序运行的代码,如果您使用的是Application特征,则该类初始化程序是应用程序的main方法代码。

App trait通过扩展DelayedInit修复所有这些。 Scala编译器明确知道此特征,因此初始化代码不是从类初始化程序运行,而是从另一个方法运行。 请注意名称引用是特征的唯一方法:

trait Helper extends DelayedInit {
  def delayedInit(body: => Unit) = {
    println("dummy text, printed before initialization of C")
    body
  }
}

在实现DelayedInit ,Scala编译器将其实现类或对象的任何初始化代码包装到for name函数中,然后将其传递给delayedInit方法。 不直接执行初始化代码。 这样,您还可以在运行初始化程序之前运行代码,这样可以让Scala将应用程序的运行时指标打印到控制台,该控制台包含在程序的入口点和退出处。 但是, 这种方法一些注意事项,因此不推荐使用DelayedInit 您应该只依赖App特性来解决Application特征所带来的问题。 您不应该直接实现DelayedInit

如果需要,您仍然可以定义main方法,只要在object定义它即可。 这主要是风格问题:

object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM