Scala主要构造函数及其生成的字段/属性 [英] Scala primary constructors and the fields/properties they generate

查看:128
本文介绍了Scala主要构造函数及其生成的字段/属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala的新手,无论我阅读了多少篇文章/教程(例如这些 | 三个 | 一个)我

New to Scala and no matter how many articles/tutorials I read (like these | three | ones) I can't seem to wrap my brain around how constructors work.

让我们在这里举三个主要构造函数的例子:

Let's take three examples of a primary constructor here:

// 1
class Fizz(buzz : Buzz) { ... }

// 2
class Fizz (val buzz : Buzz) { ... }

// 3
class Fizz (var buzz : Buzz) { ... }

对于以下每个选项:


  • buzz 属性已创建?


    • 是否公开?

    • 它可变吗?

    • 是静态的吗?

    • 是否为此创建了一个吸气剂/设置器?

    • Is a buzz property created?
      • If so, is it public?
      • Is it mutable?
      • Is is static?
      • Is a getter/setter created for it?

      • 是否公开?

      • 它可变吗?

      • 是静态的吗?

      • 是否为此创建了一个吸气剂/设置器?

      • If so, is it public?
      • Is it mutable?
      • Is is static?
      • Is a getter/setter created for it?

      推荐答案

      构造函数实际上是Scala中的野兽。实际上,Scala编译器能够为您做出一些明智的选择。

      Constructors are actually a pretty wild beast in Scala. In fact the Scala compiler is able to make some smart choices for you.

      根据您的问题的措辞,我认为您可能对Java有一定的经验。为了清楚地说明正在发生的事情-并允许您将来进行实验-让我们反编译Scala编译器生成的代码,以便我们可以看到Java的等效代码。为简洁起见,我只显示方法/字段的声明,而不显示它们的实现。

      By the phrasing of your question, I take it you probably have some experience with Java. To make it perfectly clear what's happening - and allow you to experiment yourself in the future - let's decompile the code that the Scala compiler produces so we can see the Java equivalent. For conciseness, I'll only show the declarations of the methods/fields, and not their implementation.

      class Fizz(buzz : Buzz)
      

      将编译为Java的

      public class Fizz {
          public Fizz(Buzz);
      }
      

      因为 Fizz 不会除了声明构造方法本身之外,没有声明任何引用 buzz 的方法/字段,Scala不会为其创建任何字段/方法。

      Since Fizz doesn't declare any method/field referencing buzz (apart from the constructor itself), Scala will not create any field/method for it.

      class Fizz(buzz : Buzz) {
          def foo: Buzz = buzz
      }
      

      这一次 foo 方法使用了 buzz ,因此编译器必须将其存储为字段。由于未将字段声明为 var ,因此将其设为 private final

      This time buzz is used by the foo method, and so the compiler has to store it as a field. Since the field was not declared a var, it will be made private final.

      public class Fizz {
        private final Buzz buzz;
        public Buzz foo();
        public Fizz(Buzz);
      }
      



      val 限定符



      val qualifier

      class Fizz(val buzz : Buzz)
      

      这一次,您明确表示要让嗡嗡声成为 val 。这将产生以下效果:创建一个 private final 字段来保存 buzz ,并使用相同的公共方法进行访问

      This time, you explicitly said you wanted buzz to be a val. This will have the effect of creating a private final field to hold buzz, and a public method of the same to access it.

      public class Fizz {
        private final Buzz buzz;
        public Buzz buzz();
        public Fizz(Buzz);
      }
      



      var 限定符



      var qualifier

      class Fizz(var buzz : Buzz)
      

      这种情况与上一个非常相似,只是现在您指定要修改 buzz 。这将导致Scala编译器以有趣的名称 buzz_ $ eq 为您提供setter方法。 $ shenanigan仅由于命名方法中的JVM约束而需要。在您的Scala代码中,此方法将显示为 buzz _ = ,语法糖将允许您将其称为 fizz.buzz = someBuzz 。这样,实际上看起来好像您是作为字段进行突变,但实际上您只是在调用设置器。

      This case is very similar to the previous one, except that now you're specifying that you want to be able to modify buzz. This will cause the Scala compiler to provide a setter method for you, under the funny name of buzz_$eq. The $ shenanigan is only required because of JVM constraints in naming methods. In your Scala code, this method will appear as buzz_= and syntactic sugar will allow you to call it as fizz.buzz = someBuzz. This way, it actually looks as if you're mutating as field, but you're really only calling a setter.

      public class Fizz {
        private Buzz buzz;
        public Buzz buzz();
        public void buzz_$eq(Buzz);
        public Fizz(Buzz);
      }
      



      如何反编译Scala?



      在调查此类问题时,这些命令很有用:

      How to decompile Scala?

      These commands are helpful when investigating that kind of issue:

      scalac Fizz.scala
      

      将创建一个人类难以理解的编译后的 Fizz.class 。您可以使用

      will create a compiled Fizz.class that is not human-readable. You can decompile it into a Java version using

      javap -constants -p Fizz
      

      而在包含 Fizz.class

      这篇关于Scala主要构造函数及其生成的字段/属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆