首页 文章

了解Scala中的Case类和Traits

提问于
浏览
11

我有一个如下定义的简单特征:

trait MyTrait {

  def myStringVal: String

}

我的case类实现了这个特性如下:

case class MyCaseClass(myStringVal: String) extends MyTrait {
  ...
  ...
}

来自Java世界,我发现有点难以理解MyCaseClass实际上只是通过定义MyCaseClass的参数来实现它 . 我知道你的字节代码实际上会编写getter和setter . 但如果没有var或val,这怎么可能呢?

我的理解是,如果没有var或val,则不会生成getter或setter方法 . 在这种情况下,上面的案例类MyCaseClass如何实现myStringVal方法?

有时太多的Scala魔法难以理解,特别是遗留代码 .

3 回答

  • 6

    您可能希望查看this blog article,其中涵盖了具体类型以及它们如此有用的原因 .

    在您的示例中,特性 MyTrait 没有用,除了能够像java接口一样运行 . 请注意,scala中的默认可见性是公共的 . 默认情况下,case类参数是不可变的,因此在您的示例中 val 由编译器自动推断为 myStringVal 参数 .

    案例课有什么神奇之处?!

    • 默认字段将所有构造函数参数转换为public readonly( val

    • 使用每种方法的所有构造函数参数生成 toString()equals()hashcode() 方法

    • 生成具有相同名称的伴随对象,其中包含适当的 apply()unapply() 方法,这些方法基本上只是一个方便构造函数,允许在不使用 new 关键字的情况下实例化,并且提取器默认情况下生成一个包含选项的 tuple 案例类参数 .

    EDIT: (案例)类的示例编译器输出(从scalatutorial.de复制)

    一个简单的scala类定义

    class A1(v1: Int, v2: Double)
    

    被编译为java代码

    public class A1 extends java.lang.Object implements scala.ScalaObject {
      public A1(int, double);
    }
    

    类似的案例类

    case class A2(v1: Int, v2: Double)
    

    被编译为以下java类

    public class A2 extends java.lang.Object implements 
    scala.ScalaObject,scala.Product,java.io.Serializable {
      public static final scala.Function1 tupled();
      public static final scala.Function1 curry();
      public static final scala.Function1 curried();
      public scala.collection.Iterator productIterator();
      public scala.collection.Iterator productElements();
      public double copy$default$2();
      public int copy$default$1();
      public int v1();
      public double v2();
      public A2 copy(int, double);
      public int hashCode();
      public java.lang.String toString();
      public boolean equals(java.lang.Object);
      public java.lang.String productPrefix();
      public int productArity();
      public java.lang.Object productElement(int);
      public boolean canEqual(java.lang.Object);
      public A2(int, double);
    }
    
    
    public final class A2$ extends scala.runtime.AbstractFunction2 
    implements scala.ScalaObject {
      public static final A2$ MODULE$;
      public static {};
      public scala.Option unapply(A2);
      public A2 apply(int, double);
      public java.lang.Object apply(java.lang.Object, java.lang.Object);
    }
    
  • 19

    Scala案例类为您实现了大量的样板,并且所有构造函数参数都自动公开为 val s就是其中之一 .

    如果您尝试在常规类中避免使用 val ,请执行以下操作:

    trait MyTrait {
      def myVal: String
    }
    
    class MyClass(myVal: String) extends MyTrait
    

    编译器将显示错误消息,MyClass必须是抽象的,因为它不会覆盖 myVal 方法,但是将 valvar 添加到类构造函数参数将解决该问题 .

  • 0

    案例类是不同的 - 为它们生成了一些默认方法 . 这包括参数的val getters . 将案例类视为POJO - 这是一个有用的语法糖,因为它们不需要私有成员 .

    还会生成一些其他有用的方法,例如 copytoStringapplyunapply .

相关问题