在Scala 3中不透明类型中擦除后的相同类型



我想定义两个使用相同底层类型double实现的不透明类型别名。我还想在这些别名上定义两个具有相同名称的扩展方法。以下编译:

object MyMath1:
object Logarithms1:
opaque type Logarithm1 = Double
extension (l1: Logarithm1) def foo: Unit = ()
object Logarithms2:
opaque type Logarithm2 = Double
extension (l2: Logarithm2) def foo: Unit = ()
import Logarithms1.Logarithm1
import Logarithms2.Logarithm2

然而,我希望这些扩展方法在定义不透明类型别名的范围之外定义,即在MyMath对象中:

object MyMath2:
object Logarithms1:
opaque type Logarithm1 = Double
object Logarithms2:
opaque type Logarithm2 = Double
import Logarithms1.Logarithm1
import Logarithms2.Logarithm2
extension (l1: Logarithm1) def foo: Unit = ()
extension (l2: Logarithm2) def foo: Unit = ()

这会导致以下编译错误:

Double definition:
def foo(l1: MyMath.Logarithms1.Logarithm1): Unit in object MyMath at line 52 and
def foo(l2: MyMath.Logarithms2.Logarithm2): Unit in object MyMath at line 53
have the same type after erasure.
Consider adding a @targetName annotation to one of the conflicting definitions
for disambiguation.

添加@targetName注释确实解决了问题。

我的问题:为什么第一个代码片段编译,但第二个没有?当然,在第一个代码片段中,两个方法在擦除之后也具有相同的类型。

编译后的Java类不能有两个签名(类型擦除后的名称+参数类型)一致的方法

在第一个代码片段中,方法在不同的对象中声明,因此被编译为不同类的方法,因此没有冲突。

在第二种情况下,两个方法都被呈现为同一个类的方法。由于不透明类型被编译类中的基础类型所替换,因此存在冲突(相同的名称foo,相同的擦除参数类型double)。

应用@targetName注释允许您重命名编译类中的一个或两个方法,从而消除歧义。参见与重写的关系。