在大多数情况下,它们是相同的。然而,implicit
不再用于多个不同的概念。这docs https://docs.scala-lang.org/scala3/reference/contextual/relationship-implicits.html更详细地介绍一下,但这里是它们的摘要:
Using
声明参数时,using
与以下相同implicit
。但是,当显式传递隐式参数时,您必须使用using
:
def foo(using bar: Bar) = ???
foo(using Bar()) //Cannot use just foo(Bar()) as you would in Scala 2
您还可以在 Scala 3 中使用隐式的按名称参数。
Given
Gives 也与隐式 vals/objects/methods 非常相似。
它们的一个好处是它们可以是匿名的,编译器将为它们生成一个名称,看起来像given_F_X_Y
如果给定的类型是F[X, Y]
。更多细节here https://docs.scala-lang.org/scala3/reference/contextual/relationship-implicits.html#anonymous-given-instances.
另一个变化是给定的类型必须显式编写 - 它不能像 Scala 2 中的隐式类型那样推断出来。
没有参数的给定映射到implicit object
. given 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()
不应进行不必要的计算。
而不是使用implicit def
对于隐式转换A
to B
,您现在可以定义给定的Conversion[A, B] http://dotty.epfl.ch/api/scala/Conversion.html实例。
你还可以在Dotty中使用隐式类,但是你可以直接定义扩展方法 https://docs.scala-lang.org/scala3/reference/contextual/extension-methods.html。虽然扩展内部的方法不能采用自己的类型参数,但它们比隐式类更易于使用。
Scala 3 中的另一个变化 -summon
是一个像这样的方法implicitly
,但它可以返回比所请求的类型更具体的类型。