Получение аргументов командной строки в чертах Scala - PullRequest
4 голосов
/ 06 декабря 2011

У меня есть большое количество простых 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
}

Это компилируется, но завершается неудачно с NPE, когда наступает момент разыменования args, вероятно, потому, что черта App еще не инициализирована. Изменение порядка признаков и изменение наследования App в BaseScript для объявления собственного типа ничего не делают, как и эксперименты с DelayedInit. Объявление компонентов как «ленивых» в BaseScript будет работать, но я также хотел бы, чтобы эти компоненты фактически использовались во время инициализации (например, настройка каталогов журналов и загрузка классов драйверов JDBC на основе конфигурации), поэтому преимущества лени теряются. Что я могу сделать, чтобы аргументы командной строки были видимы и инициализированы в признаке BaseScript?

Ответы [ 3 ]

4 голосов
/ 06 декабря 2011

Я думаю, что вам лучше всего поменять черту BaseScript на класс по двум причинам.Во-первых, по сравнению с классами, инициализация признака выполняется в обратном порядке .См. этот вопрос о поведении инициализации .Во-вторых, 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
  }
}
3 голосов
/ 06 декабря 2011

Вы пытались использовать ленивый val (а не расширять черту App)?

trait BaseScript { self : App =>
  lazy val configuration = loadConfiguration(args(0))
  //setup a bezillion components, usable from any of the scripts
  //based on the configuration
}
1 голос
/ 06 декабря 2011

Глядя на App источник , кажется, что вы можете переопределить main для выполнения действий с аргументами до запуска кода приложения:

trait AppUtil extends App {
  def myInit(args: Array[String]) {
    println("args " + args.size)
  }
  override def main(args: Array[String]) {
    myInit(args)
    super.main(args)
  }
}

Я подозреваю, что AppИсточник может дать вам вдохновение, чтобы переписать свой собственный App.Код на самом деле не такой длинный, и у вас будет больше контроля над такими вещами, как то, что вы делаете с args, что происходит до и после запуска main.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...