了解Scala中的Case类和Traits

时间:2014-03-31 18:18:57

标签: scala

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

trait MyTrait {

  def myStringVal: String

}

实现此特征的我的案例类如下:

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

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

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

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

3 个答案:

答案 0 :(得分:19)

您可能需要查看this blog article,了解具体的案例类别以及它们如此有用的原因。

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

案例类的 magic 是做什么的?!

  • 默认字段
  • 将所有构造函数参数转换为public readonly(val
  • 使用每种方法的所有构造函数参数生成toString()equals()hashcode()方法
  • 生成具有相同名称的伴随对象,其中包含适当的apply()unapply()方法,这些方法基本上只是一个便利构造函数,允许在不使用new关键字的情况下实例化,并使用提取器default生成案例类参数的选项包装tuple

编辑:(案例)类的示例编译器输出(从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);
}   

答案 1 :(得分:6)

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

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

trait MyTrait {
  def myVal: String
}

class MyClass(myVal: String) extends MyTrait

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

答案 2 :(得分:0)

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

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