我正在尝试使用Option.getOrElse()
方法,但它返回的是Any
或ScalaObject
,而不是Option
参数化的正确类的实例。我找不到任何关于这个问题的提及,它似乎不应该存在。我做错了什么?
class MyClass {
def isOk = true
}
val myVal = Some(new MyClass) // :Option[MyClass]
val check = myVal.getOrElse(false).isOk
无法调用isOk
方法,因为它尝试在Any
上调用它。
答案 0 :(得分:17)
您正尝试在isOk
和MyClass
(Boolean
)的基类上调用方法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
) - false
。 MyClass
和Boolean
的唯一常见类型是...... 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]
,因为Any
是MyClass
和Boolean
中最具体的常见类型。
将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
。 (在您的情况下,A
为MyClass
且B
为Boolean
)。
作为一个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所建议的模式匹配。