[英]In Scala; should I use the App trait?
我刚刚开始学习Scala,我正在遵循的许多教程都使用了一种main
方法的不同表示形式的组合。 除了熟悉的主要方法; 还有使用特征App
或Application
。 看来Application
已被弃用,不推荐使用,但我找不到任何有关这些定义入口点的方法的信息。
所以,我想知道是否有人可以向我解释:
App
和Application
的特性如何工作? Application
, App
特性有何不同? 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.