我正在尝试以下方法:
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
上。发生了什么事?
答案 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
这表示Option
和pending
都不是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)
不幸的是,其他两个当前的答案并没有解释真正的问题。
如果mPending
和mPublished
的类型为Option[Edit]
,那么您的代码应该可以使用,尽管它非常简单。但是由于类型擦除,published: Option[Edit]
只能测试published
是Option
(在编译时你应该得到关于未经检查的类型参数的警告!)。由于前两行排除它为None
(至少mPending
是Option
),因此它是Some
,因此published.get
会返回结果。要在此结果上调用isSuspended
,Scala必须将其强制转换为Edit
。但是从异常消息看来,这个结果似乎是None
;也就是说,mPublished
是Some(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
}
}