Scala推断:1次评估失败,中间值成功
我是scala的初学者,不明白这里发生了什么: 鉴于:Scala推断:1次评估失败,中间值成功,scala,type-inference,Scala,Type Inference,我是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) 它起作用了 现在,如果我这样
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)
它起作用了
现在,如果我这样做:
val b:Boolean = reverse.map(_.isNaire).getOrElse(false)
它无法编译,类型不匹配:找到任何必需的布尔值
编辑:谢谢铍,通过制作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)
}
注意:scala编译器是2.10.2在
scala.Predef
中,有一个从java.lang.Boolean
到scala.Boolean
的隐式转换:
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
def works:Boolean = testValue.map[Boolean](_.naire).getOrElse(false)
因此,在第一种情况下,val v:Option[Boolean]=reverse.map(u.isNaire)
编译器看到的是一个java.lang.Boolean
,并在范围内寻找一个隐式方法将其转换为scala.Boolean
,它可以方便地在scala.Predef
中找到
在第二种情况下,testValue.map(u.naire).getOrElse(false)
,编译器按以下顺序执行操作:
Option[Test]=>Option[java.lang.Boolean]
getOrElse[B>:A](默认值:=>B):B
其中A
是java.lang.Boolean
,B
是Any
,因为scala.Boolean
不是:
java.lang.Boolean
valb:Boolean
,编译器找不到从Any
到scala.Boolean的隐式转换
scala.Predef
到java.lang.Boolean
的隐式转换:
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
def works:Boolean = testValue.map[Boolean](_.naire).getOrElse(false)
这是一个常见问题,经常会弹出,因为map
后跟getOrElse
非常方便。若要在不使用额外类型的情况下正确修复此问题,请在选项上使用折叠(变形):
def worksToo:Boolean = testValue.fold(false)(_.naire)
通过使用fold
您可以获得一些额外的类型安全性,因为没有转换到普通类型。例如,您不能这样做:
def failsTypeCheck = testValue.fold("test")(_.naire)
虽然编译器对此没有问题:
def passesTypeCheck = testValue.map(_.naire).getOrElse("test")
java.lang.Boolean
和scala.Boolean
不一样。为了弥补这个差距,您必须提供一个隐式转换可以完成其工作的位置
有一些模式可以处理这些类型的Java/Scala互操作性问题:
- 如果可以从Scala端使用不同的方法,则可以使用隐式值类:
对象容器{
隐式类Test2Scala(val-test:test)扩展了AnyVal{
def naireForScala:Boolean=test.naire
}
}
其他类{
val testValue=Some(新测试(真))
进口集装箱_
def神秘编译错误:布尔=
testValue.map(u.naireForScala).getOrElse(false)
}
这在运行时不需要额外的实例。它只是提供了另一种方法来丰富Java类
- 如果可以派生子类,则可以使用
DummyImplicit
,保留方法的名称:
类Test2(\u-naire:Boolean)扩展了Test(\u-naire){
def naire(隐式di:dummy隐式):布尔=\u naire
}
其他类{
val testValue=Some(新的Test2(true))
def神秘编译错误:布尔=
testValue.map(u.naire).getOrElse(false)
}
要获得不同的方法签名,需要使用DummyImplicit
。这有点棘手,在运行时需要一个额外的实例,但是Test2
是一个Test
(就OOP而言)
- 将Java实例包装到Scala实例中:
类TestWrapper(test:test){
def naire:Boolean=test.naire
}
其他类{
val testValue=Some(新TestWrapper(新测试(true)))
def神秘编译错误:布尔=
testValue.map(u.naire).getOrElse(false)
}
需要一个额外的实例,您必须添加委托,
TestWrapper
不是一个Test
,但它很简单。我可以编译一个修改过的版本,所以请提供一个。您最好在map()函数文本中将java.lang.Boolean转换为scala.Boolean,因为false
不是java.lang.Boolean
的值。例如,def神秘编译错误:Boolean=testValue.map(u.naire==true).getOrElse(false)
IntelliJ IDEA提醒我,.map(u.predicate).getOrElse(false)
可以简化为.exists(u.predicate)
,这比对布尔人使用fold
更好@很好,它告诉了我同样的事情,我只是没有注意到:)