问题 隐含的转换怪异


我试图理解为什么一个隐式转换在一个案例中起作用,而在另一个案例中却没有。 这是一个例子:

   case class Wrapper[T](wrapped: T)
   trait Wrapping { implicit def wrapIt[T](x: Option[T]) = x.map(Wrapper(_))

   class NotWorking extends Wrapping { def foo: Option[Wrapper[String]] = Some("foo") }

   class Working extends Wrapping { 
      def foo: Option[Wrapper[String]] = {
        val why = Some("foo")
        why
      }
    }

基本上,我有一个隐含的转换 Option[T] 至 Option[Wrapper[T]],我正在尝试定义一个函数,它返回一个可选的字符串,它被隐式包装。

问题是为什么,当我试图返回时 Option[String] 直接(NotWorking 上面),我收到一个错误(found : String("foo") required: Wrapper[String]),如果我在返回之前将结果分配给val,那就消失了。

是什么赋予了?


10448
2018-05-15 14:05


起源



答案:


我不知道这是故意还是被认为是一个错误,但这是我认为正在发生的事情。

def foo: Option[Wrapper[String]] = Some("foo") 编译器将设置提供的参数的预期类型 Some( ) 如 Wrapper[String]。然后它看到你提供了一个 String 这不是预期的,所以它寻找隐式转换 String => Wrapper[String],找不到一个,失败了。

为什么它需要预期的类型,而不仅仅是键入 Some("foo") 如 Some[String] 和 之后 试着找一个转换? 因为scalac希望能够检查以下代码:

case class Invariant[T](t: T)
val a: Invariant[Any] = Invariant("s")

为了使此代码有效,编译器不能只键入 Invariant("s") 如 Invariant[String] 因为然后编译将失败 Invariant[String] 不是的子类型 Invariant[Any]。编译器需要设置期望的类型 "s" 至 Any 所以它可以看到 "s" 是一个实例 Any 在为时已晚之前。

为了使这段代码和你的代码能够正确运行,我认为编译器需要一些它似乎没有的回溯逻辑,也许是有充分理由的。

你的原因 Working 代码确实有效,这种类型推断不会跨越多行。类似地 val a: Invariant[Any] = {val why = Invariant("s"); why} 不  编译。


10
2018-05-15 14:38