重载解析的更改
Scala 3 中的重载解析在三个方面改进了 Scala 2。首先,它考虑了所有参数列表,而不仅仅是第一个参数列表。其次,它可以推断函数值的参数类型,即使它们在第一个参数列表中。第三,默认参数不再与优先级相关。
查看第一个参数列表之外
重载解析现在可以考虑参数列表,以便在选择一组重载备选方案时进行选择。例如,以下代码在 Scala 3 中编译,而在 Scala 2 中会导致歧义重载错误
def f(x: Int)(y: String): Int = 0
def f(x: Int)(y: Int): Int = 0
f(3)("") // ok
以下代码也编译通过
def g(x: Int)(y: Int)(z: Int): Int = 0
def g(x: Int)(y: Int)(z: String): Int = 0
g(2)(3)(4) // ok
g(2)(3)("") // ok
为了使此工作正常进行,SLS §6.26.3 中的重载解析规则进行了如下增强
在一个函数应用于多个参数列表的情况下,如果重载解析在考虑
n >= 1
个参数列表时产生多个竞争性备选方案,则解析将使用n + 1
个参数列表重新尝试。
此更改的动机是新的语言特性 扩展方法,其中需要根据额外的参数块进行重载解析。
函数值的类型参数
对缺少类型参数的函数值的处理已得到改进。现在,我们可以将此类值传递给重载应用程序的第一个参数列表,前提是剩余的参数足以选择重载函数的变体。例如,以下代码在 Scala 3 中编译通过,而在 Scala 2 中会导致缺少类型参数错误
def f(x: Int, f2: Int => Int) = f2(x)
def f(x: String, f2: String => String) = f2(x)
f("a", _.toUpperCase)
f(2, _ * 2)
为了使此方法起作用,SLS §6.26.3 中的重载解析规则进行了如下修改
替换句子
否则,令
S1,...,Sm
为通过使用未定义的预期类型对每个参数进行类型化而获得的类型向量。
使用以下段落
否则,令
S1,...,Sm
为所有参数类型的已知类型的向量,其中参数E
的已知类型如下确定
- 如果
E
是一个缺少某些类型参数的函数值(p_1, ..., p_n) => B
,则E
的已知类型为(S_1, ..., S_n) => ?
,其中每个S_i
都是参数p_i
的类型(如果给出),否则为?
。这里?
代表一个通配符类型,它与任何其他类型兼容。 - 否则,
E
的已知类型是使用未定义的预期类型对E
进行类型化后的结果。
模式匹配闭包
{ case P1 => B1 ... case P_n => B_n }
被视为已扩展为函数值
x => x match { case P1 => B1 ... case P_n => B_n }
因此也用 ? => ?
类型近似。
默认参数不再与优先级相关
在 Scala 2 中,如果在多个应用性备选方案中,一个备选方案具有默认参数,则该备选方案将从考虑范围中删除。这具有不幸的副作用,即向方法的参数添加默认值可能会使该方法在重载调用中不可见。
Scala 3 取消了这种区别。具有默认参数的方法不会被视为比其他方法具有更低的优先级。