在 Scala 中实例化特征的两种方法

eje*_*211 2 scala traits anonymous-class

我知道有两种方法可以创建匿名类来实例化 Scala 中的特征:

scala> trait SomeTrait {
     |   def aUsefulMethod = ()
     | }
defined trait SomeTrait

scala> val instance1 = new SomeTrait{} // Method 1
instance1: SomeTrait = $anon$1@7307556f

scala> instance1.aUsefulMethod // Returns a Unit.

scala> object instance2 extends SomeTrait // Method 2
defined module instance2

scala> instance2.aUsefulMethod // Returns a Unit.
Run Code Online (Sandbox Code Playgroud)

我想不出它们不相等的原因。我错了吗?

我问这个问题的部分原因是我以前只知道方法 2,但现在我发现方法 1 更常见。所以我想知道我是否一直做错了什么。

And*_*ann 5

第一种方法new Trait {}创建一个新class实例。

第二种方法创建一个object单例。

人们可以在 REPL 中看到这一点:

定义特质

scala> trait Example {}
defined trait Example
Run Code Online (Sandbox Code Playgroud)

新的匿名类

每次调用 new 都会返回一个新的实例。可以看到每个对象都有一个新地址。

scala> new Example{}
res0: Example = $anon$1@768debd

scala> new Example{}
res1: Example = $anon$1@546a03af
Run Code Online (Sandbox Code Playgroud)

对象扩展特征

这里单例对象被创建一次。

scala> object X extends Example
defined object X

scala> X
res2: X.type = X$@1810399e

scala> X
res3: X.type = X$@1810399e
Run Code Online (Sandbox Code Playgroud)

影响与比较

即使这两种方法表面上看起来相似,但它们会导致不同的结果。

scala> new Example{} == new Example{}
<console>:12: warning: comparing values of types Example and Example using `==' will always yield false
   new Example{} == new Example{}
                 ^
 res4: Boolean = false

 scala> X == X
 res5: Boolean = true
Run Code Online (Sandbox Code Playgroud)

更深入

在底层结构上,这两种方法都会导致*class在运行时生成不同的文件JVM

匿名类

    $ cat example.scala 
    object Example1 {
      trait A
      new A {}
    }

    $ scalac example.scala 

    $ ls *class

      Example1$$anon$1.class Example1$A.class
      Example1$.class        Example1.class         

    $ cat example2.scala 
    object Example2 {
      trait A

      object X extends A
    }

    $ scalac example2.scala 

    $ ls *class
    Example2$.class   Example2$X$.class
    Example2$A.class  Example2.class 
Run Code Online (Sandbox Code Playgroud)