13

Scala 类的“伴生对象”可以被视为具有与类相同的完全限定名称的单例对象(即同名,在同一个包中)。它们用于保存类的所有实例共有的实用函数,作为 Javastatic方法的替代品。

但是,在文档和问题的各个地方,它都说必须在同一个编译单元中定义伴随对象。例如,它们必须在同一个文件中定义;不能为 Java 对象定义伴生对象在 REPL 中,它们必须在同一输入行上定义,因此会出现警告消息:

warning: previously defined class Foo is not a companion to object Foo.
Companions must be defined together; you may wish to use :paste mode for this.

这意味着在类及其伴生对象之间必须有区别,而只是具有相同(完全限定)名称的类和对象。这个区别是什么?

4

1 回答 1

17

让我们调用这个类class SomeClass(尽管它也可以是例如 a trait)。

私人会员

伴随对象 ( object SomeClass)的方法可以访问的实例的私有方法/数据class SomeClass

如果您的伴生对象仅使用您的类的公共接口(例如仅定义常量),则没有实际区别。但是在许多情况下,让实用程序函数访问私有成员很有用。例如,object SomeClass可以定义一个工厂方法apply来设置 的私有成员class SomeClass,而不必在公共接口中公开 setter。因此,在这种情况下,您必须通过将 的定义object SomeClassclass SomeClass.

另一个区别是编译器在类型(及其超类型)的伴随对象中搜索隐式。因此,如果您使用在 的代码中定义的隐式转换class SomeClass,则必须在伴随对象中定义它们。

评论

两者的结合也解释了相同编译单元的限制。

  • scalacobject SomeClass在它知道class SomeClass它调用的私有成员之前无法编译。
  • scalacclass SomeClass在它知道它调用什么隐式之前无法编译。所以伴生对象必须在不迟于class SomeClass.

因此它们必须同时编译。此外,当前的编译器显然单独编译单独的文件(参见缺乏对跨多个文件拆分类的支持),将其限制在同一个编译单元中。

于 2012-07-22T22:01:06.163 回答