【问题标题】:Failed implicit resolution for Nothing with <:<使用 <:< 的 Nothing 的隐式解析失败
【发布时间】:2020-09-09 02:14:35
【问题描述】:

以下代码无法在 Scala 2.12 / 2.13 上编译。为什么?

class X[U, T]

object X {
  implicit def genericX[U, T](implicit ev: T <:< U): X[U, T] = new X[U, T]
}

implicitly[X[AnyRef, String]]  // compiles
implicitly[X[String, Nothing]] // does not compile

【问题讨论】:

  • 感谢@dmytro-mitin,我知道+T 解决了这个问题,但不幸的是,这不是我可以接受的。事实上,我想要T 逆变,但即使在不变量的情况下也卡住了。
  • 为什么需要X?现在它基本上是&lt;:&lt; 的同义词。为什么不能直接使用&lt;:&lt;?为什么需要为Nothing 解析隐式? Nothing 如何出现在您的代码中?
  • 有点复杂,和stackoverflow.com/questions/61890200/…有关。最终我想有一个方法def check[T](....): A[T] = ??? 以便check(...) 返回A[Any]check[String](...) 返回A[String]。 (即Any 推断为默认类型,而不是Nothing)。我尝试了以下方法:def check[T](implicit ev: X[Any, T]): A[T] = ??? 因此X[U, -T].
  • 感谢您的反馈!让我画出整个画面:A[T] 在内部捕获 ClassTag[T]。我正在寻找一种方法def attribute[T](s: String): A[T],它在缺少T 时返回A[SomeDefaultType](或者甚至Any,以使事情变得更简单)。我确实有一个可行的解决方案 (gist.github.com/kamilkloch/a5c97d0c7cdec47f8dc4c4ac4c131674),但是,它需要一个中间类来咖喱类型参数。我希望通过上述X[U, -T] 摆脱它。

标签: scala implicit


【解决方案1】:

长话短说,编译器不喜欢在隐式中推断Nothing

Why doesn't Scala's implicit class work when one of the type parameters should be Nothing?

Implicit error when trying to implement the `Absurd` typeclass

https://www.reddit.com/r/scala/comments/73791p/nothings_twin_brother_the_better_one/

http://guillaume.martres.me/talks/typelevel-summit-oslo/?fbclid=IwAR1yDSz-MetOgBh0uWMeuBuuL6wlD79fN_4NrxAtl3c46JB0fYCYeeGgp1Y#/9(幻灯片 10“Nothing 的恐惧”)

https://www.youtube.com/watch?v=YIQjfCKDR5A?t=459 (7:39)

https://www.youtube.com/watch?v=lMvOykNQ4zs

Nothing的恐惧

  • scalac 急切地实例化,即使它不安全

  • 通过从不推断Nothing来平衡

    class Foo[T] { def put(x: T) = {} }
    (new Foo).put("") // T? = String
    
  • 如果下限不是Nothing则失败

    class Foo[T >: Null] { def put(x: T) = {} }
    (new Foo).put("") // T? = Null
    // type mismatch: Null does not match String
    
  • 有时候你真的很想推断Nothing

    class Foo[T]
    def foo[T](x: Foo[T]) = x
    foo(new Foo[Nothing]) // error
    

解决方法是引入类型Bottom

type Bottom <: Nothing

implicitly[Bottom =:= Nothing]
implicitly[Nothing =:= Bottom]

implicitly[X[AnyRef, String]]  // compiles
// implicitly[X[String, Nothing]] // does not compile
implicitly[X[String, Bottom]] // compiles

【讨论】:

  • 很遗憾,implicitly[ClassTag[Bottom]] 不起作用...
  • @KamilKloch 尝试添加implicit val bottomClassTag: ClassTag[Bottom] = new ClassTag[Bottom] { override def runtimeClass: Class[_] = implicitly[ClassTag[Nothing]].runtimeClass }
  • 谢谢,它的工作更加简单。但最终,Bottom 技巧对X[U, -T] 的类型推断没有帮助,请看一下:gist.github.com/kamilkloch/d4950417ee420fc3fc2a31089b918ef4
猜你喜欢
  • 2021-03-02
  • 2021-06-03
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多