代码之家  ›  专栏  ›  技术社区  ›  K J

Scala:编译器能有效地优化常量吗?

  •  4
  • K J  · 技术社区  · 11 年前

    让我们考虑以下几点:

    object Foo {
      val BUFFER_SIZE = 1024
    }
    
    class Foo {
      .
      .
      .
    
      val buffer = new Array[Byte](Foo.BUFFER_SIZE)
    

    这太过冗长,与Java的静态(最终)变量相比似乎并不优雅,尤其是因为常量的定义和用法相距太远,无法立即理解代码。我想要的是这样的东西:

    class Foo {
      val BUFFER_SIZE = 1024
    
      val buffer = new Array[Byte](BUFFER_SIZE)
    

    问题是,Scala编译器是否足够聪明,不会为Foo的每个实例实例化BUFFER_SIZE来浪费时间和空间?还是应该选择第一个?

    2 回复  |  直到 11 年前
        1
  •  6
  •   om-nom-nom    11 年前

    TLDR:不,它不是很好,但你可以指导编译器。

    而且检查起来很容易(我把代码放到test.scala中):

    scalac test.scala 
    javap Foo.class
    // Compiled from "test.scala"
    // public class Foo {
    //   public int BUFFER_SIZE();
    //   public byte[] buffer();
    //   public Foo();
    // }
    

    所以val最终成为了一个getter方法。现在让我们看看实际的字节码:

    javap -c Foo.class
    Compiled from "test.scala"
    public class Foo {
      public int BUFFER_SIZE();
        Code:
           0: aload_0       
           1: getfield      #15                 // Field BUFFER_SIZE:I
           4: ireturn       
    
      // .... irrelevant parts
    

    正如你所看到的 getfield 代码,这意味着每个类实例都有不同的实例(与 getstatic 这意味着访问静态变量)。 高度优化的代码看起来像

    public final int BUFFER_SIZE();
        Code:
           0: sipush        1024
           3: ireturn 
    

    如果将BUFFER_SIZE标记为 final 修改器:

    class Foo {
      final val BUFFER_SIZE = 1024
    
      val buffer = new Array[Byte](BUFFER_SIZE)
    }
    

    预混合字段 private[this] 正如@ghik所说,这也会起到作用。不同之处在于 最终的 使用琐碎的代码生成getter,而 私人的[这个] 直接内联值。

        2
  •  2
  •   ghik    11 年前

    它永远不会像这样优化,因为它是一个必须从外部(例如Java)可用的成员。

    唯一的情况是 也许 被优化(在未来)是当它被声明为 private[this] :

    class Foo {
      private[this] val BUFFER_SIZE = 1024
      val buffer = new Array[Byte](BUFFER_SIZE)
    }
    

    无论如何,我还是要说的是,使用伴侣对象。