例如,我有一个类 Value 和一个隐式函数将字符串转换为Value:
case class Value(v: String)
implicit def strToValue(s: String): Value = Value(s)
这是一个具有方法返回值的特征:
trait ReturnValue {
def f: Value
}
因为隐式转换存在,我只需返回一个字符串文字即可实现方法 f :
object Obj1 extends ReturnValue {
override def f: Value = "123"
}
当然返回一个String类型的变量就可以了:
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
这里的类型推断似乎失败了。未推断出类型 String ,然后无法匹配隐式转换。 (完整档案为here)
我尝试过其他具有类型参数的函数,例如“map”,它们都能很好地工作。
为什么Option.getOrElse如此特殊以至于类型推断在这里失败了?
答案 0 :(得分:2)
此变体导致相同的编译错误,并可能显示编译器如何解构表达式:
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")
似乎编译器将Value
的转换应用于getOrElse
的参数,而不是其结果。事实是可以通过启用scalacOptions in Compile ++= Seq("-Xprint-types", "-Xprint:typer")
的输出来确认(清理了一点 - 删除了明显不相关的注释):
private [this] val v:Value =
vs.getOrElse {[B>:String](默认值:=> B)B} [java.io.Serializable] {(默认值:=> java.io.Serializable)java.io.Serializable} ( strToValue {(s:String)Value}(" 234" {String(" 234")}){Value} ){
我认为推论的工作原理如下:
vs
类型称为Some[String]
getOrElse
声明为def getOrElse[B >: A](default: => B): B
(此处A
为String
)B
推断为Value
,因为这是表达式的预期结果类型。Value
和String
最具体的超类型为Serializable
您还可以注意完全删除隐式转换时的行为方式。 val v: Value = vs.getOrElse("234")
的错误是:类型不匹配;
发现:字符串(" 234")
必需:值
答案 1 :(得分:0)
这似乎是一个编译器错误。这是一个显示奇怪行为的例子。
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的输出解释为Serializable