【问题标题】:Implicit conversions weirdness隐式转换怪异
【发布时间】:2017-05-15 14:05:14
【问题描述】:

我试图理解为什么隐式转换在一种情况下确实有效,但在另一种情况下却无效。 这是一个例子:

   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,它就会消失。

什么给了?

【问题讨论】:

    标签: scala implicit-conversion


    【解决方案1】:

    我不知道这是有意的还是会被视为错误,但这是我认为正在发生的事情。

    在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} 不会编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-11
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多