在 GitHub 上编辑此页面

隐式转换 - 更多细节

实现

从类型 S 到类型 T 的隐式转换或视图由以下任一定义

  • 一个 implicit def,其类型为 S => T(=> S) => T
  • 一个隐式值,其类型为 Conversion[S, T]

标准库定义了一个抽象类 Conversion

package scala
@java.lang.FunctionalInterface
abstract class Conversion[-T, +U] extends Function1[T, U]:
  def apply(x: T): U

函数字面量会自动转换为 Conversion 值。

视图在三种情况下应用

  1. 如果表达式 e 的类型为 T,而 T 不符合表达式的预期类型 pt。在这种情况下,会搜索一个适用于 e 且其结果类型符合 pt 的隐式 v。搜索过程与隐式参数的情况相同,其中隐式范围是 T => pt 的范围。如果找到这样的视图,则表达式 e 会转换为 v(e)
  2. 在类型为 T 的选择 e.m 中,如果选择器 m 不表示 T 的可访问成员。在这种情况下,将搜索一个适用于 e 且其结果包含名为 m 的可访问成员的视图 v。搜索过程与隐式参数的情况相同,其中隐式范围是 T 的范围。如果找到这样的视图,则选择 e.m 将转换为 v(e).m
  3. 在类型为 T 的应用 e.m(args) 中,如果选择器 m 表示 T 的一些可访问成员,但这些成员中没有一个适用于参数 args。在这种情况下,将搜索一个适用于 e 且其结果包含一个适用于 args 的方法 m 的视图 v。搜索过程与隐式参数的情况相同,其中隐式范围是 T 的范围。如果找到这样的视图,则应用 e.m(args) 将转换为 v(e).m(args)

与 Scala 2 隐式转换的差异

在 Scala 2 中,参数按值传递的视图优先于参数按名称传递的视图。在 Scala 3 中不再是这种情况。在应用此规则的 Scala 2 中,将发出报告歧义转换的类型错误。

implicit def conv1(x: Int): String = x.toString
implicit def conv2(x: => Int): String = x.toString

val x: String = 0 // Compiles in Scala2 (uses `conv1`),
                  // type error in Scala 3 because of ambiguity.

在 Scala 2 中,函数类型的隐式值将被视为潜在的视图。在 Scala 3 中,这些隐式值需要具有类型 Conversion

// Scala 2:
def foo(x: Int)(implicit conv: Int => String): String = x

// Becomes with Scala 3:
def foo(x: Int)(implicit conv: Conversion[Int, String]): String = x

// Call site is unchanged:
foo(4)(_.toString)

// Scala 2:
implicit val myConverter: Int => String = _.toString

// Becomes with Scala 3:
implicit val myConverter: Conversion[Int, String] = _.toString

请注意,隐式转换也受到 Scala 2 和 Scala 3 之间隐式解析更改 的影响。

更改的动机

在 Scala 3 中引入 scala.Conversion 以及将此类型的隐式值限制为潜在视图的决定,源于从语言中消除意外行为的愿望。

implicit val m: Map[Int, String] = Map(1 -> "abc")

val x: String = 1  // Scala 2: assigns "abc" to x
                   // Scala 3: type error

此代码段包含类型错误。val x 的右侧不符合类型 String。在 Scala 2 中,编译器将使用 m 作为从 IntString 的隐式转换,而 Scala 3 将报告类型错误,因为 Map 不是 Conversion 的实例。

迁移路径

用作视图的隐式值应将其类型更改为Conversion

有关受隐式解析更改影响的隐式转换的迁移,请参阅隐式解析中的更改以获取更多信息。

参考

有关隐式解析的更多信息,请参阅隐式解析中的更改。其他详细信息可在PR #2065中找到。