Scala-Spark - Try/Catch 正在改变案例类型 class

Scala-Spark - Try/Catch is changing type of case class

我正在尝试使用 sellmerfud.optparse 来解析用于启动 Spark2-Submit jar 文件的参数。我在下面粘贴的代码适用于粘贴到 spark2-shell 中,我在其中强制 args 值,因为它们将通过命令行传递。

问题是,当我使用 try/catch 时,我设置的变量没有分配给 class,但是当我不使用 try/catch 时,args 数组解析良好并且值可用我正在粘贴我在 spark2-shell 会话中捕获的内容以提供信息以查看正在发生的事情。

  import org.sellmerfud.optparse._
  case class Config(keyVal: String            = "tst",
                  startDate: String          = "",
                  endDate: String            = "")
  var args = Array("-k","testkey","-s","2018-01-01","-e","2018-03-31")
  var clsCfg = try {
    new OptionParser[Config] {
      banner = "testargs [options] file...\n"
      separator("")
      separator("Options: ")
      reqd[String]("-k <string>", "--keyval <string>", "Enter Key Value")
          { (v, cfg) => cfg.copy(keyVal = v) }
      optl[String]("-s", "--startdate <date>", "Enter date in mm-dd-yyyy format.")
          { (v, cfg) => cfg.copy(startDate = v.toString()) }
      optl[String]("-e", "--enddate <date>", "Enter date in mm-dd-yyyy format.")
          { (v, cfg) => cfg.copy(endDate = v.toString) }
    }.parse(args, Config())
  } catch { case e: OptionParserException => println(e.getMessage); java.lang.System.exit(1) }
  println("clsCfg: " + clsCfg)
  println("\nArguments passed as array, one array element per row:")
  println(args.deep.mkString("\n"))
  println("clscfg.keyVal: " + clsCfg.keyVal)

以上代码输出的行数:

import org.sellmerfud.optparse._
defined class Config
args: Array[String] = Array(-k, testkey, -s, 2018-01-01, -e, 2018-03-31)
clsCfg: Any = Config(testkey,Some(2018-01-01),Some(2018-03-31))
clsCfg: Config(testkey,Some(2018-01-01),Some(2018-03-31))
Arguments passed as array, one array element per row:
-k
testkey
-s
2018-01-01
-e
2018-03-31
<console>:42: error: value keyVal is not a member of Any
           println("clscfg.keyVal" + clsCfg.keyVal)

但是当我如下删除 try/catch 行时:

  import org.sellmerfud.optparse._
  case class Config(keyVal: String            = "tst",
                  startDate: String          = "",
                  endDate: String            = "")
  var args = Array("-k","testkey","-s","2018-01-01","-e","2018-03-31")
  var clsCfg =
    new OptionParser[Config] {
      banner = "testargs [options] file...\n"
      separator("")
      separator("Options: ")
      reqd[String]("-k <string>", "--keyval <string>", "Enter Key Value")
          { (v, cfg) => cfg.copy(keyVal = v) }
      optl[String]("-s", "--startdate <date>", "Enter date in mm-dd-yyyy format.")
          { (v, cfg) => cfg.copy(startDate = v.toString()) }
      optl[String]("-e", "--enddate <date>", "Enter date in mm-dd-yyyy format.")
          { (v, cfg) => cfg.copy(endDate = v.toString) }
    }.parse(args, Config())

  println("clsCfg: " + clsCfg)
  println("\nArguments passed as array, one array element per row:")
  println(args.deep.mkString("\n"))
  println("clscfg.keyVal: " + clsCfg.keyVal)

我得到了这些解析字符串的结果,但更重要的是,它创建了变量 clsCfg,我可以在其中轻松访问 class 成员。

import org.sellmerfud.optparse._
defined class Config
args: Array[String] = Array(-k, testkey, -s, 2018-01-01, -e, 2018-03-31)
clsCfg: Config = Config(testkey,Some(2018-01-01),Some(2018-03-31))
clsCfg: Config(testkey,Some(2018-01-01),Some(2018-03-31))
Arguments passed as array, one array element per row:
-k
testkey
-s
2018-01-01
-e
2018-03-31
clscfg.keyVal: testkey   

我认为我需要 try/catch 来正确处理提交的格式错误的变量,但我不知道如何让它工作。感谢任何帮助。

可以在示例中说明发生了什么。基本上,当您使用 try..catch 时,scala 将查看所有代码块的每个 return 类型(try 和所有 catch,因为可能有多个)和 return 一种对所有这些都通用的类型。在您的情况下,它是 Any。示例:

val a  =  try { 1 } // a will be of type Int
val b =   try { 1 } catch { _ => 2 } // b will be of type Int
val c =   try { 1 } catch { _ => "blah" } // c will be of type Any

如果你想要更多 scala-ish 的方式来处理它,你可以按照评论中的建议使用 Try() monad,但你可以构建一个 returns Option[Config]

def buildConfig(args:Array[String]):Option[Config] = try { 
 Some(new OptionParser[Config] {
  ....
  }.parse(args, Config())
} catch { _ => None }   

请注意,try 和 catch return 都是 Option,因为 Some()None 都是 Option。 然后使用模式匹配来确保处理成功

buildConfig(args) match {
     case Some(conf) => // normal processing
     case None => //
}

如另一个答案中所述,try 语句的 return 类型是 try 和所有 catch 块结果中的常见类型。您的 try 结果是 Config,但是您的 catch 结果是 Unit(因为它没有 return 任何值),它们的常见类型是Any。您可以尝试向您的函数添加显式 return 类型,它会编译失败(隐式类型通常很有用,往往会隐藏这样的错误)。

您可以 return 一个 Option[Config] 类型(使用 catch 块 returning None,以及正常处理 return ing Some(config)), 或者,如果你想保留异常信息,你可以使用 Either type:

val clsCfg: Either[Config, Throwable] = try {
  ...
  Left(config)
} catch  { case e: OptionParserException => Right(e) }

您稍后可以匹配的:

clsCfg match {
  case Left(config) => // use your config here
  case Right(exception) => // handle exception
}