我是scala的初学者,不明白这里发生了什么:
鉴于:
val reverse:Option[MyObject] = ...
myObject.isNaire
返回布尔值。
如果我这样做:
val v:Option[Boolean] = reverse.map(_.isNaire)
val b:Boolean = v.getOrElse(false)
有效。
现在,如果我这样做:
val b:Boolean = reverse.map(_.isNaire).getOrElse(false)
无法使用type mismatch: found Any, required Boolean
编辑:感谢Beryllium,通过制作SSCCE,我找到了解释的开始。在第一个示例中,myObject是一个java类,因此isNaire是一个java.lang.Boolean。我认为隐式转换应该使这个透明,所以解释仍然是受欢迎的。
class Test(val naire:java.lang.Boolean)
class Other {
val testValue = Some(new Test(true))
def mysteriousCompilationError:Boolean = testValue.map(_.naire).getOrElse(false)
}
注意:ScalaCompiler是2.10.2
答案 0 :(得分:5)
在scala.Predef
中,存在从java.lang.Boolean
到scala.Boolean
的隐式转换:
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
因此,在第一种情况val v:Option[Boolean] = reverse.map(_.isNaire)
中,编译器会看到java.lang.Boolean
,并在范围内查找隐式方法,将其转换为scala.Boolean
,它可以方便地在scala.Predef
中找到}。
在第二种情况下,testValue.map(_.naire).getOrElse(false)
,编译器按此顺序执行操作:
Option[Test] => Option[java.lang.Boolean]
getOrElse[B >: A](default: => B): B
其中A
为java.lang.Boolean
而B
为Any
,因为scala.Boolean
不是>:
java.lang.Boolean
val b:Boolean
,编译器无法找到从Any
到scala.Boolean
的隐式转换解决此问题的唯一方法是在映射操作期间告诉编译器使用scala.Predef
的隐式转换从java.lang.Boolean
转到scala.Boolean
:
def works:Boolean = testValue.map[Boolean](_.naire).getOrElse(false)
这是一个常见问题并经常弹出,因为map
后跟getOrElse
非常便利。要在没有额外类型的情况下正确修复此问题,请在选项上使用fold
(catamorphism):
def worksToo:Boolean = testValue.fold(false)(_.naire)
通过使用fold
,您可以获得一些类型安全性,因为没有转换为常见类型。例如,你不能这样做:
def failsTypeCheck = testValue.fold("test")(_.naire)
虽然编译器没有问题:
def passesTypeCheck = testValue.map(_.naire).getOrElse("test")
答案 1 :(得分:0)
java.lang.Boolean
和scala.Boolean
不一样。为弥合差距,您必须提供隐式转换可以起作用的位置。
有一些模式可以处理这些类型的Java / Scala互操作性问题:
object Container {
implicit class Test2Scala(val test: Test) extends AnyVal {
def naireForScala: Boolean = test.naire
}
}
class Other {
val testValue = Some(new Test(true))
import Container._
def mysteriousCompilationError: Boolean =
testValue.map(_.naireForScala).getOrElse(false)
}
这在运行时不需要额外的实例。它只是提供了另一种丰富Java类的方法。
DummyImplicit
来保留方法的名称:class Test2(_naire: Boolean) extends Test(_naire) {
def naire(implicit di: DummyImplicit): Boolean = _naire
}
class Other {
val testValue = Some(new Test2(true))
def mysteriousCompilationError: Boolean =
testValue.map(_.naire).getOrElse(false)
}
获取不同的方法签名需要DummyImplicit
。这有点棘手,在运行时需要一个额外的实例,但Test2
是Test
(就OOP而言)。
class TestWrapper(test: Test) {
def naire: Boolean = test.naire
}
class Other {
val testValue = Some(new TestWrapper(new Test(true)))
def mysteriousCompilationError: Boolean =
testValue.map(_.naire).getOrElse(false)
}
需要一个额外的实例,您必须添加代理,TestWrapper
不是Test
,但它很简单。