为什么在Scala中对Option.getOrElse的返回值使用隐式转换时类型推断失败?
例如,我有一个类值和一个隐式函数将字符串转换为值:为什么在Scala中对Option.getOrElse的返回值使用隐式转换时类型推断失败?,scala,Scala,例如,我有一个类值和一个隐式函数将字符串转换为值: case class Value(v: String) implicit def strToValue(s: String): Value = Value(s) 下面是一个trait,它有一个方法返回值: trait ReturnValue { def f: Value } 由于存在隐式转换,我可以通过只返回字符串文字来实现方法f: object Obj1 extends ReturnValue { override def f:
case class Value(v: String)
implicit def strToValue(s: String): Value = Value(s)
下面是一个trait,它有一个方法返回值:
trait ReturnValue {
def f: Value
}
由于存在隐式转换,我可以通过只返回字符串文字来实现方法f:
object Obj1 extends ReturnValue {
override def f: Value = "123"
}
当然,返回一个字符串类型的变量就可以了:
object Obj2 extends ReturnValue {
override def f: Value = {
val v = Some("123").getOrElse("234")
v
}
}
但是当我试图直接使用Option.getOrElse的结果作为返回值时:
object Obj3 extends ReturnValue {
override def f: Value = Some("123").getOrElse("234") // Compilation error: type mismatch
}
发生编译错误:
Error:(23, 50) type mismatch;
found : java.io.Serializable
required: Entry.Value
override def f: Value = Some("123").getOrElse("234") // Compilation error: type mismatch
这里的类型推断似乎失败了。未推断类型字符串,因此无法匹配隐式转换。(完整文件为)
我尝试过其他带有类型参数的函数,比如“map”,它们都工作得很好
为什么Option.getOrElse如此特殊以致于这里的类型推断失败?此变体会导致相同的编译错误,并可能显示编译器如何解构表达式:
object Obj3 extends ReturnValue {
override def f: Value = {
val v = Some("123") // is of type Some(String)
v.getOrElse("234": Value) // Compilation error: type mismatch
}
}
同样的错误也可以在没有任何特征的情况下通过以下简单的重新编程实现:
case class Value(v: String)
implicit def strToValue(s: String): Value = Value(s)
val vs = Some("123")
val v: Value = vs.getOrElse("234")
编译器似乎在getOrElse
的参数上,而不是在其结果上,将转换应用于值。事实上,可以通过在Compile++=Seq(“-Xprint-types”,“-Xprint:typer”)
中启用scalacOptions的输出来确认DO(清除了一点-删除了明显不相关的注释):
私有[此]值v:值=
vs.getOrElse{[B>:String](默认值:=>B)B}[java.io.Serializable]{(默认值:=>java.io.Serializable)java.io.Serializable}(strotvalue{(s:String)Value}(“234”{String(“234”)}{Value}){
我认为推论如下:
vs
类型称为Some[String]
getOrElse
声明是def getOrElse[B>:A](默认值:=>B):B
(A
在这里是String
)
- 编译器将
B
推断为值
,因为这是表达式的预期结果类型
Value
和String
最具体的超类型是Serializable
您还可以注意到当您完全删除隐式转换时它的行为。val v:Value=vs.getOrElse(“234”)
的错误是:类型不匹配;
找到:字符串(“234”)
必需:Value这似乎是一个编译器错误。下面是一个显示奇怪行为的示例
case class ValString(string: String)
object ValString {
implicit def string2ValString(string: String): ValString = ValString(string)
}
case class ValThing( one: ValString, two: ValString, three: ValString, four: ValString, five: ValString)
val opt = Option("aString")
val x = ValThing(
if(opt.isEmpty) "" else opt.get,
opt.fold("")(identity),
opt.orElse(Option("")).get,
opt.getOrElse(""): String,
ValString(opt.getOrElse(""))
)
然而,上述所有措施都有效
val x = ValThing( opt.getOrElse(""), .... )
失败,因为它将getOrElse的输出解释为可序列化的有趣的。这些变体确实有效:覆盖def:Value=Some(“123”:Value”)。getOrElse(“234”)
和覆盖def:Value=None。getOrElse(“234”)
甚至覆盖def:Value=Some(“123”).get
。我不知道答案,但我通常通过键入casting方法来解决此问题def:Value=Some(“123”).getOrElse[String](“234”)
,以确保在最后可能的时刻完成转换。我认为问题与以下事实有关:getOrElse
作为按名称调用参数,它必须与类型推断和隐式转换解析进行巧妙的交互。