上下文抽象 的重新设计带来了一些不兼容性。
不兼容性 | Scala 2.13 | Scala 3 迁移重写 | Scalafix 规则 | 运行时不兼容性 |
---|---|---|---|---|
隐式 def 的类型 | ✅ | |||
隐式视图 | 可能 | |||
视图边界 | 弃用 | |||
在 A 和 => A 上的转换不明确 |
隐式定义的类型
隐式定义的类型(val
或 def
)需要在 Scala 3 中显式给出。它们不能再被推断了。
名为 ExplicitResultTypes 的 Scalafix 规则可以自动编写缺少的类型注释。
隐式视图
Scala 3 不支持从隐式函数值(形式为 implicit val ev: A => B
)进行隐式转换。
以下代码段在 Scala 3 中现在无效
trait Pretty {
val print: String
}
def pretty[A](a: A)(implicit ev: A => Pretty): String =
a.print // In Scala 3, Error: value print is not a member of A
Scala 3 迁移编译 可以针对这些情况发出警告,但不会尝试修复它。
请注意,此不兼容性可能会产生运行时不兼容性并破坏您的程序。实际上,编译器可以从更广泛的作用域中找到另一个隐式转换,这最终会导致在运行时出现不需要的行为。
已解析的转换取决于编译器模式
-source:3.0-migration
:编译器执行ev
转换-source:3.0
:编译器无法执行ev
转换,但可以执行anyPretty
,这是不需要的
在 Scala 3 中,一个简单的修复方法是明确提供正确的转换
def pretty[A](a: A)(implicit ev: A => Pretty): String =
- a.print
+ ev(a).print
视图界限
视图界限已弃用很长时间,但仍在 Scala 2.13 中受支持。它们不再可以与 Scala 3 一起编译。
def foo[A <% Long](a: A): Long = a
在此示例中,在 Scala 3 中,我们收到以下错误消息
-- Error: src/main/scala/view-bound.scala:2:12
2 | def foo[A <% Long](a: A): Long = a
| ^
| view bounds `<%' are deprecated, use a context bound `:' instead
该消息建议使用上下文界限而不是视图界限,但这会更改方法的签名。保留二进制兼容性可能更容易且更安全。要做到这一点,必须显式声明并调用隐式转换。
小心不要陷入上面在 隐式视图 中描述的运行时不兼容性。
-def foo[A <% Long](a: A): Long = a
+def foo[A](a: A)(implicit ev: A => Long): Long = ev(a)
在 A
和 => A
上的模棱两可的转换
在 Scala 2.13 中,在 A
上的隐式转换优于在 => A
上的隐式转换。在 Scala 3 中不再是这样,并导致模棱两可的转换。
例如,在此示例中
implicit def boolFoo(bool: Boolean): Foo = ???
implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???
true.foo()
Scala 2.13 编译器选择 boolFoo
转换,但 Scala 3 编译器无法编译。
-- Error: src/main/scala/ambiguous-conversion.scala:4:19
9 | true.foo()
| ^^^^
|Found: (true : Boolean)
|Required: ?{ foo: ? }
|Note that implicit extension methods cannot be applied because they are ambiguous;
|both method boolFoo in object Foo and method lazyBoolFoo in object Foo provide an extension method `foo` on (true : Boolean)
一个临时解决方案是显式编写转换。
implicit def boolFoo(bool: Boolean): Foo = ???
implicit def lazyBoolFoo(lazyBool: => Boolean): Foo = ???
-true.foo()
+boolFoo(true).foo()