Scala案例陈述失败

时间:2016-08-26 14:24:06

标签: scala

我正在尝试以下方法:

SELECT "device_authorisation_change"('TestDevice');

据我所知,如果它到达最后def getStatus: MyStatus = { (mPending, mPublished) match { case (None, None) => MyStatus.inactive case (pending: Option[Edit], None) => MyStatus.neverPublished case (None, published: Option[Edit]) => if (published.get.isSuspended) MyStatus.suspended else MyStatus.published case (pending: Option[Edit], published: Option[Edit]) => if (published.get.isSuspended) MyStatus.suspendedWithChanges else MyStatus.publishedWithChanges } } ,则case都不应该是Option,但我得到以下内容:

None

投放在play.api.UnexpectedException: Unexpected exception[ClassCastException: null] .... Caused by: java.lang.ClassCastException: scala.None$ cannot be cast to com.fredley.Edit 上。发生了什么事?

3 个答案:

答案 0 :(得分:2)

注意:@ AlexeyRomanov在下面的回答是正确的。我已更新此答案,以包含更深入,更正确的信息。

选项,部分和无

您可以通过更简单的示例更好地了解Option的工作原理。在这里,实际为Option的{​​{1}}通过了第一个案例,并且仅在第二个案例中被捕获:

None

由于val foo: Option[String] = None foo match { case x: Option[String] => "Yep! It's an option!" case None => "Foo is None!" } // res0: String = Yep! It's an option! 实际上是None的子类,因此Option值将与None匹配。正确的解决方案是使用Option[String]

Some(String)

这只是背景:看起来你有一个嵌套的foo match { case Some(String) => "It's a string!" case None => "Foo is None!" } // res0: String = Foo is None!

  

scala.None $无法转换为com.fredley.Edit

这表示Optionpending都不是published,而且确实是None,但由于类型删除,匹配无法区分。例如:

Option[<something>]

即使它不匹配val foo: Option[String] = None val bar: Option[String] = Option("fubar") for (x <- List(foo, bar)) x match { case x: Option[Int] => println(s"It's a string=$x") case None => println(s"It is None!") case _ => println("No match found.") } ,上面也会打印:

Option[Int]

有关条件

的说明

虽然您可以像现在一样嵌入条件语句,但案例匹配允许您将它们包含在案例中:

It's a string=None
It's a string=Some(fubar)

因此,您可以将代码转换为:

val suspended = true
foo match {
  case x: Some[String] => "It's a string!"
  case None if suspended => "None but suspended!"
  case None => "Foo is None!"
}  // res0: String = None but suspended!

这可能会或可能不会更容易解析,但如果您发现条件分支变得不透明,则可以选择。

答案 1 :(得分:2)

不幸的是,其他两个当前的答案并没有解释真正的问题。

如果mPendingmPublished的类型为Option[Edit],那么您的代码应该可以使用,尽管它非常简单。但是由于类型擦除,published: Option[Edit]只能测试publishedOption(在编译时你应该得到关于未经检查的类型参数的警告!)。由于前两行排除它为None(至少mPendingOption),因此它是Some,因此published.get会返回结果。要在此结果上调用isSuspended,Scala必须将其强制转换为Edit。但是从异常消息看来,这个结果似乎是None;也就是说,mPublishedSome(None),其真实类型类似于Option[Option[Edit]](它也可能类似于Option[Any])。

现在,考虑到所有这些,正确的解决方案接近@TheKojuEffect的:

def getStatus: MyStatus = {
  (mPending, mPublished) match {
    case (None, None) => MyStatus.inactive
    case (_, None) => MyStatus.neverPublished
    case (None, Some(published)) => if (published.isSuspended) MyStatus.suspended else MyStatus.published
    case (_, Some(published)) =>
      if (published.isSuspended)
        MyStatus.suspendedWithChanges
      else
        MyStatus.publishedWithChanges
  }
}

也就是说,您应该使用Some(published)模式,,但让Scala弄清楚published的类型是什么。如果上面的假设是正确的,编译器会发现它是Option[Edit](或Any),并说它没有isSuspended方法。在此之后,您可以弄清楚如何修复代码:更改匹配项上方的行以使mPublished成为Option[Edit]而不是?将模式更改为Some(Some(published))?还有别的吗?

答案 2 :(得分:1)

使用Some代替Option应该有效。

  def getStatus: MyStatus = {
    (mPending, mPublished) match {
      case (None, None) => MyStatus.inactive
      case (Some(pending: Edit), None) => MyStatus.neverPublished
      case (None, Some(published: Edit) => if (published.get.isSuspended) MyStatus.suspended else MyStatus.published
      case (Some(pending: Edit), Some(published:Edit)) =>
          if (published.get.isSuspended)
            MyStatus.suspendedWithChanges
          else
            MyStatus.publishedWithChanges
    }
  }