在斯卡拉;我应该使用App特性吗? [英] In Scala; should I use the App trait?

查看:69
本文介绍了在斯卡拉;我应该使用App特性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始学习Scala,我正在关注的许多教程都将不同表示形式的组合用于main方法.除了熟悉的主要方法外,还使用了特征AppApplication. 看来Application已被弃用,不建议使用,但是我找不到任何有关这些定义入口点的方法的详细说明.

I've just started learning Scala and many of the tutorials that I'm following are using a combination of different representations for a main method. Aside from the familiar main method; there's also the use of traits App or Application. It appears that Application has been deprecated and is not recommended, but I can't find any information that explains much beyond this about each of these ways to define an entry point.

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

So, I'm wondering if someone could explain to me:

  • 特征AppApplication如何工作?
  • 为什么不再推荐使用特征Application?App特征有什么不同?
  • 在哪里应使用传统的main方法,何时应使用App来启动程序?两种方法有什么区别?
  • How do the traits App and Application work?
  • Why is the trait Application no longer recommended and what does the App trait do that is different?
  • Where should I use the traditional main method and when should I use App to start my program? What's the difference between the two approaches?

推荐答案

The problem with the Application trait is actually described in its documentation:

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

(1) Threaded code that references the object will block until static initialization is complete. However, because the entire execution of an object extending Application takes place during static initialization, concurrent code will always deadlock if it must synchronize with the enclosing object.

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

This is a tricky one. If you extend the Application trait, you are basically creating a Java class:

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

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

The JVM runs the above class initializer implicitly synchronized on the MyApplication class. This way, it is assured that no instance of MyApplication is created before its class is initialized. If you spawn a thread from your application that again needs to access an instance of MyApplication, your application would dead lock as the class initialization is only complete after the entire program has executed. This implies a paradox as no instance can be created as long as your program is running.

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

(2) As described above, there is no way to obtain the command-line arguments because all code in body of an object extending Application is run as part of the static initialization which occurs before Application's main method even begins execution.

类初始化器不接受任何参数.同样,它会先运行,然后再将任何值传递给该类,因为在您甚至可以分配一个静态字段值之前,都需要执行该类初始化程序.因此,通常会在main方法上收到的args丢失.

A class initializer does not take any arguments. Also, it is run first, before any values could be handed to the class as the class initializer needs to be executed before you could even assign a static field value. Thus, the args that you normally receive on a main method are lost.

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

(3) Static initializers are run only once during program execution, and JVM authors usually assume their execution to be relatively short. Therefore, certain JVM configurations may become confused, or simply fail to optimize or JIT the code in the body of an object extending Application. This can lead to a significant performance degradation.

JVM会优化经常运行的代码.这样,可以确保没有浪费时间,而这并不是真正造成性能瓶颈的方法.但是,可以安全地假定static方法仅执行一次,因为它们无法手动调用.因此,如果使用Application特性,它将不会优化从类初始化程序运行的代码,而该类初始化程序是应用程序的main方法代码.

The JVM optimizes code that is run frequently. This way, it makes sure that no run time is wasted on methods that are not really a performance bottle neck. However, it safely assumes that static methods are only executed once as they cannot be invoked manually. Thus, it will not optimize the code that is run from a class initializer which is however your application's main method code if you are using the Application trait.

App 特性通过扩展 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.

When implementing DelayedInit, the Scala compiler wraps any initialization code of its implementing class or object into a for name function which is then passed to the delayedInit method. No initialization code is executed directly. This way, you can also run code before an initializer is run what allows Scala for example to print an application's runtime metrics to the console which is wrapped around the program's entry point and exit. However, there are some caveats of this approach and using DelayedInit is therefore deprecated. You should really only rely on the App trait which solves the problems that are imposed by the Application trait. You should not implement DelayedInit directly.

如果愿意,您仍然可以定义main方法,只要在object中定义它即可.这主要是样式问题:

You can still define a main method if you want to, as long as you define it in an object. This is mostly a matter of style:

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

这篇关于在斯卡拉;我应该使用App特性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆