【问题标题】:Difference between Scala 2 implicits and Scala 3 given/usingScala 2 隐式和 Scala 3 给定/使用之间的区别
【发布时间】:2021-03-23 23:52:09
【问题描述】:

Scala 2 中的 implicit 关键字和 Scala 3 中的 given+using 有什么区别?是implicit被分成了两个关键字,还是语义也不同,如果是,如何?

【问题讨论】:

    标签: scala implicit scala-3


    【解决方案1】:

    在大多数情况下,它们是相同的。但是,implicit 不再用于多个不同的概念。 docs 更详细,但这里是它们的摘要:

    使用

    声明参数时,usingimplicit 相同。但是,当显式传递隐式参数时,必须使用using

    def foo(using bar: Bar) = ???
    foo(using Bar()) //Cannot use just foo(Bar()) as you would in Scala 2
    

    您还可以在 Scala 3 中使用隐式按名称参数。


    给定

    Givens 也非常类似于隐式 vals/objects/methods。

    关于它们的一个好处是它们可以是匿名的,编译器将为它们生成一个名称,如果给定的类型是F[X, Y],它看起来类似于given_F_X_Y。更多详情here.

    另一个变化是给定的类型必须显式编写 - 它不能像 Scala 2 中的隐式那样推断出来。

    没有参数的给定映射到implicit objectgiven foo: Foo with {...} 变成了 implicit object foo extends Foo {...}

    带有参数的给定类似于implicit def,它只接受更多implicit 参数。

    given listOrd[T](using ord: Ord[T]): Ord[List[T]] with { ... }
    //^^ this maps to this vv
    class listOrd[T](implicit ord: Ord[T]) extends Ord[List[T]] { ... }
    final implicit def listOrd[T](implicit ord: Ord[T]): listOrd[T] = new listOrd[T]
    

    仅是别名的给定如果只是引用,则变为 implicit def,否则变为 implicit lazy val

    val foo: Foo
    given Foo = foo
    

    会变成final implicit def given_Foo = foo(注意编译器生成的名称),但是

    given foo: Foo = new Foo()
    

    会变成final implicit lazy val foo: Foo = new Foo(),因为不应不必要地计算new Foo()


    您现在可以定义一个给定的Conversion[A, B] 实例,而不是使用implicit def 进行从AB 的隐式转换。

    你仍然可以在 Dotty 中使用隐式类,但你可以直接定义extension methods。虽然扩展中的方法不能采用自己的类型参数,但它们比隐式类更易于使用。

    Scala 3 中的另一个变化 - summon 是类似 implicitly 的方法,但它可以返回比所请求的类型更具体的类型。

    【讨论】:

      【解决方案2】:

      语义也不同。在 Scala 2 中,Not 可以使用歧义技巧来定义

      trait Not[A]
      object Not {
        implicit def default[A]: Not[A] = null
        implicit def ambig[A](implicit a: A): Not[A] = null
      }
      
      implicitly[Not[Int]] // compiles
      
      implicit val s: String = null
      // implicitly[Not[String]] // doesn't compile
      

      但在 Scala 3 中这不起作用,因为歧义错误不会传播

      trait Not[A]
      object Not {
        given [A]: Not[A] = null
        given [A](using a: A): Not[A] = null
        // given ambig[A](using a: A): Not[A] = null
      }
      
      summon[Not[Int]] // compiles
      
      given String = null
      summon[Not[String]] // compiles
      

      应该改用scala.util.NotGiven

      summon[NotGiven[Int]] // compiles
      
      given String = null
      // summon[NotGiven[String]] // doesn't compile
      

      (在 3.0.0-M3-bin-20201211-dbc1186-NIGHTLY 中测试)

      http://dotty.epfl.ch/docs/reference/contextual/givens.html#negated-givens

      http://dotty.epfl.ch/docs/reference/changed-features/implicit-resolution.html

      【讨论】:

      • 很好,我没有想到这个!我认为隐式解析中的更改页面上还有一个示例,说明在 Scala 3 中,歧义错误如何无法让搜索成功
      猜你喜欢
      • 1970-01-01
      • 2013-06-16
      • 2018-08-22
      • 2011-12-07
      • 2021-02-19
      • 2019-04-25
      • 1970-01-01
      • 2014-09-29
      • 2010-11-17
      相关资源
      最近更新 更多