Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在Scala中对Option.getOrElse的返回值使用隐式转换时类型推断失败?_Scala - Fatal编程技术网

为什么在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
作为按名称调用参数,它必须与类型推断和隐式转换解析进行巧妙的交互。