在 Scala 特征中获取命令行参数 [英] Getting command-line arguments in Scala traits

查看:65
本文介绍了在 Scala 特征中获取命令行参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有大量简单的命令行 Scala 应用程序,它们共享相当多的通用结构.它们都继承自 scala.App,这很好.我想将这些命令行应用程序的共享结构重构为一个共同的特征,然后我可以将其继承到我的(更简单的)命令行应用程序类中.问题在于一些常见结构包括命令行参数的解析.

I've got a large number of simple command-line Scala apps which share quite a bit of common structure. All of them inherit from scala.App, which is just fine. I would like to refactor out the shared structure of these command-line Apps into a common trait, which I could then inherit into my (much simpler) command-line app classes. The problem arises in that some of the common structure includes parsing of command-line arguments.

object MyScript extends BaseScript with App{
   //small bits of business logic using components defined in BaseScript
}

trait BaseScript extends App{
    val configuration = loadConfiguration(args(0))
    //setup a bezillion components, usable from any of the scripts, based on the configuration
}

这可以编译,但在实际取消引用 args 时会因 NPE 失败,大概是因为 App 特征尚未初始化.改变 trait 顺序并将 BaseScript 中 App 的继承更改为自类型声明没有任何作用,就像 DelayedInit 的实验一样.在 BaseScript 中将组件声明为lazy"是可行的,但我也希望在初始化期间实际使用这些组件(例如,根据配置设置日志目录和加载 JDBC 驱动程序类),因此失去了惰性的好处.我可以做些什么来使命令行参数在 BaseScript trait 中可见并初始化?

This compiles, but fails with an NPE when it comes time to actually dereference args, presumably because the App trait hasn't yet been initialized. Changing trait orders and changing the inheritance of App in BaseScript to be a self-type declaration do nothing, as have experiments with DelayedInit. Declaring the components as "lazy" in BaseScript would work, but I also wish need to actually use those components during initialization (e.g., setting up log directories and loading JDBC driver classes based on the configuration), so the benefits of laziness are lost. Is there something I can do to get the command-line arguments visible and initialized in the BaseScript trait?

推荐答案

我认为最好的办法是将 BaseScript 特性更改为类,原因有两个.首先是与类相比,特征初始化以相反的顺序执行.请参阅有关初始化行为的这个问题.其次,BaseScript 在语义上更像是一个超类而不是附加行为.我想你会发现这可以简化事情.

I think your best bet is to change your BaseScript trait into a class for two reasons. The first is that compared with classes, trait initializations are executed in reverse order. See this question on initialization behavior. Second, BaseScript semantically is more of a superclass than additional behavior. I think you will find that this can simplify things.

在执行MyScript 时,以下代码首先初始化BaseScript 类.BaseScript 依次依赖于 App trait 并强制它首先初始化.

When executing MyScript, the following code initializes the BaseScript class first. BaseScript is dependent on the App trait in turn and forces it to initialize first.

object MyScript extends BaseScript {
  //small bits of business logic using components defined in BaseScript
  println( "running" )
  println( "arg(0): " + configuration )
}

class BaseScript extends App {
  val configuration = loadConfiguration(args)
  //setup a bezillion components, usable from any of the scripts, based on the configuration
  def loadConfiguration( args: Array[String] ) = {
    println( "configuring" )
    if ( args.length > 0 ) args(0) else null
  }
}

这篇关于在 Scala 特征中获取命令行参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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