Scala - Option.getOrElse()“类型擦除”?

时间:2012-05-22 11:03:01

标签: scala option type-erasure

我正在尝试使用Option.getOrElse()方法,但它返回的是AnyScalaObject,而不是Option参数化的正确类的实例。我找不到任何关于这个问题的提及,它似乎不应该存在。我做错了什么?

class MyClass {

  def isOk = true

}

val myVal = Some(new MyClass) // :Option[MyClass]

val check = myVal.getOrElse(false).isOk

无法调用isOk方法,因为它尝试在Any上调用它。

7 个答案:

答案 0 :(得分:17)

您正尝试在isOkMyClassBoolean)的基类上调用方法Any

试试这个:

scala> class MyClass(b: Boolean) { def isOk = b }
defined class MyClass

scala> val myVal = Some(new MyClass(true))
myVal: Some[MyClass] = Some(MyClass@35d56bbe)

scala> myVal.map{_.isOk}.getOrElse(false)
res0: Boolean = true

scala> myVal.getOrElse(new MyClass(false)).isOk
res1: Boolean = true

答案 1 :(得分:8)

按设计工作。这个表达式:

myVal.getOrElse(false)

返回未展开的MyClass实例或(如果Option实际为None) - falseMyClassBoolean的唯一常见类型是...... Any。这就是你所看到的。

为了实现这一点,您必须从MyClass返回与getOrElse()兼容的内容:

myVal.getOrElse(new MyClass).isOk

或许你想实现 null-object 模式:

object MyClass {
  val Empty = new MyClass
}

myVal.getOrElse(MyClass.Empty).isOk

答案 2 :(得分:6)

您正在使用Boolean在Option [MyClass]中应用getOrElse,因此,它们的公共超类是Any。

你应该模式匹配:

val check = myVal match {
  case Some(c) => c.isOk
  case None => false
} 

答案 3 :(得分:4)

您正在getOrElse上致电Option[MyClass]。您将Boolean作为参数传递给getOrElse。会发生什么事情是Scala正在将该选项翻译为Option[Any],因为AnyMyClassBoolean中最具体的常见类型。

MyClass(或MyClass的子类)传递给getOrElse而不是false

答案 4 :(得分:1)

因为你的getOrElse可能返回false,MyClass和false的常见类型是Any。

答案 5 :(得分:1)

Jhonny Everson是对的。模式匹配就是答案。在这种情况下,他的答案中的模式相当于exists

scala> Some(new MyClass) :: None :: Nil map(_.exists(_.isOK))
res12: List[Boolean] = List(true, false)

答案 6 :(得分:1)

因此,当“可选”值为Option[A]时,您有一个A => B,一个函数B和一个默认None,并且您想要结束使用B。 (在您的情况下,AMyClassBBoolean)。

作为一个Haskeller,我认为首先要做的是hoogle。回想一下,在Haskell中,Option被称为Maybe。所以我们hoogle Maybe a -> (a -> b) -> b -> b,最热门的是maybe :: b -> (a -> b) -> Maybe a -> b,这正是我们想要的。

data MyClass = MyClass { isOK :: Bool }
newMyClass = MyClass { isOK = true }

myVal = newMyClass
check = maybe False isOK myVal

那很好,但是Scala怎么样?好吧,相当于hoogle的Scala是Scalex。我搜索了Scalex Option[A] => B => (A => B) => B,但无济于事。因此,让我们看看如何在Haskell中实现maybe函数。您可以按照hoogle中的相应链接找到来源。

maybe :: b -> (a -> b) -> Maybe a -> b
maybe n _ Nothing  = n
maybe _ f (Just x) = f x

似乎很容易转换成Scala

def option[A, B](opt: Option[A])(n: B)(f: A => B) = opt match {
  case None => n
  case Some(x) => f(x)
}

然后可以这样使用:

val check = option(myVal)(false)(_.isOK)

如果你想通过较少的currying或者拉皮条选择类,你必须要求Scala专家比我更专业,但请注意这基本上归结为Jhonny Everson所建议的模式匹配。