在 GitHub 上编辑此页面

通用应用方法

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 的类,也会生成构造函数代理。具体规则如下

  1. 为具体类 C 创建了一个构造函数代理伴生对象 object C,前提是该类还没有伴生对象,并且在定义 C 的作用域中没有定义或继承其他名为 C 的值或方法。

  2. 为具体类生成了构造函数代理 apply 方法,前提是

    • 该类有一个伴生对象(可能已在步骤 1 中生成),并且
    • 该伴生对象尚未定义名为 apply 的成员。

    每个生成的 apply 方法都转发到该类的某个构造函数。它具有与构造函数相同的类型和值参数。

构造函数代理伴生对象本身不能用作值。必须使用 apply 选择代理伴生对象(或将其应用于参数,在这种情况下,apply 会隐式插入)。

构造函数代理也不允许遮盖正常定义。也就是说,如果

  • 标识符解析为构造函数代理,
  • 同一个标识符也在其他作用域中定义或导入,
  • 其他引用可以应用于(可能为空的)参数列表。也就是说,它引用一个方法或一个包含应用方法作为成员的值。

动机

省略 new 隐藏了一个实现细节,使代码更易于阅读。即使它需要一个新规则,但它可能会增加语言的感知规则性,因为案例类已经提供了函数调用创建语法(并且通常仅为此原因而定义)。

本文中