我有大量的简单Scala命令行应用程序,它们共享很多通用结构。它们全部都继承自scala.App,这很好。我想将这些命令行应用程序的共享结构重构为一个共同的特征,然后可以将其继承到我的(更简单的)命令行应用程序类中。出现问题的原因在于某些通用结构包括命令行参数的解析。
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
特性尚未初始化。更改特征顺序和将BaseScript中App的继承更改为自类型声明,就像使用DelayedInit进行实验一样。在BaseScript中将组件声明为“惰性”是可行的,但我也希望在初始化期间实际使用这些组件(例如,根据配置来设置日志目录和加载JDBC驱动程序类),因此失去了懒惰的好处。我可以做些什么来使命令行参数在BaseScript特性中可见并初始化吗? 最佳答案
我认为您最好的选择是将您的BaseScript
特性更改为类,这有两个原因。首先是与类相比,特征初始化以相反的顺序执行。请参见this question on initialization behavior。其次,从语义上讲,BaseScript
更多的是超类,而不是其他的行为。我认为您会发现这可以简化事情。
当执行MyScript
时,以下代码首先初始化BaseScript
类。 BaseScript
依次取决于App
特性,并强制其首先进行初始化。
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
}
}