通用应用方法
Scala case 类生成 apply 方法,以便可以使用简单的函数应用创建 case 类的值,而无需编写 new
。
Scala 3 将此方案推广到所有具体类。示例
class StringBuilder(s: String):
def this() = this("")
StringBuilder("abc") // old: new StringBuilder("abc")
StringBuilder() // old: new StringBuilder()
之所以可行,是因为会与类一起生成具有两个 apply
方法的伴生对象。该对象如下所示
object StringBuilder:
inline def apply(s: String): StringBuilder = new StringBuilder(s)
inline def apply(): StringBuilder = new StringBuilder()
合成对象 StringBuilder
及其 apply
方法称为构造函数代理。即使对于 Java 类和来自 Scala 2 的类,也会生成构造函数代理。具体规则如下
-
为具体类
C
创建了一个构造函数代理伴生对象object C
,前提是该类还没有伴生对象,并且在定义C
的作用域中没有定义或继承其他名为C
的值或方法。 -
为具体类生成了构造函数代理
apply
方法,前提是- 该类有一个伴生对象(可能已在步骤 1 中生成),并且
- 该伴生对象尚未定义名为
apply
的成员。
每个生成的
apply
方法都转发到该类的某个构造函数。它具有与构造函数相同的类型和值参数。
构造函数代理伴生对象本身不能用作值。必须使用 apply
选择代理伴生对象(或将其应用于参数,在这种情况下,apply
会隐式插入)。
构造函数代理也不允许遮盖正常定义。也就是说,如果
- 标识符解析为构造函数代理,
- 同一个标识符也在其他作用域中定义或导入,
- 其他引用可以应用于(可能为空的)参数列表。也就是说,它引用一个方法或一个包含应用方法作为成员的值。
动机
省略 new
隐藏了一个实现细节,使代码更易于阅读。即使它需要一个新规则,但它可能会增加语言的感知规则性,因为案例类已经提供了函数调用创建语法(并且通常仅为此原因而定义)。
本文中