Yan*_*gne 2 scala type-inference
我是scala的初学者,不明白这里发生了什么:
鉴于:
val reverse:Option[MyObject] = ...
Run Code Online (Sandbox Code Playgroud)
并myObject.isNaire返回布尔值.
如果我做 :
val v:Option[Boolean] = reverse.map(_.isNaire)
val b:Boolean = v.getOrElse(false)
Run Code Online (Sandbox Code Playgroud)
这行得通.
现在,如果我这样做:
val b:Boolean = reverse.map(_.isNaire).getOrElse(false)
Run Code Online (Sandbox Code Playgroud)
它无法编译 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)
}
Run Code Online (Sandbox Code Playgroud)
注意:ScalaCompiler是2.10.2
在scala.Predef有从隐式转换java.lang.Boolean到scala.Boolean:
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
Run Code Online (Sandbox Code Playgroud)
因此,在第一种情况下val v:Option[Boolean] = reverse.map(_.isNaire),编译器会看到a java.lang.Boolean并在范围内查找隐式方法,将其转换为a 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.Booleanval b:Boolean,编译器不能找到一个隐式转换Any到scala.Boolean要解决这个问题的唯一办法,就是在地图操作过程中告诉编译器使用隐式转换,从scala.Predef从去java.lang.Boolean到scala.Boolean:
def works:Boolean = testValue.map[Boolean](_.naire).getOrElse(false)
Run Code Online (Sandbox Code Playgroud)
这是一个常见问题,经常出现,因为map其后getOrElse非常便利.要在没有额外类型的情况下正确修复此问题,请fold对选项使用(catamorphism):
def worksToo:Boolean = testValue.fold(false)(_.naire)
Run Code Online (Sandbox Code Playgroud)
通过使用,fold您可以获得一些额外的类型安全性,因为没有转换到常见类型.例如,你不能这样做:
def failsTypeCheck = testValue.fold("test")(_.naire)
Run Code Online (Sandbox Code Playgroud)
虽然编译器对此没有问题:
def passesTypeCheck = testValue.map(_.naire).getOrElse("test")
Run Code Online (Sandbox Code Playgroud)