理解Scala中的案例类别和特征
我有一个简单的特点,定义如下:理解Scala中的案例类别和特征,scala,Scala,我有一个简单的特点,定义如下: trait MyTrait { def myStringVal: String } 我实现此特性的case类如下所示: case class MyCaseClass(myStringVal: String) extends MyTrait { ... ... } 来自Java世界,我发现仅仅通过定义MyCaseClass的一个参数来理解MyCaseClass实际上实现了这一点有点困难。我知道你的字节码实际上会编写getter和setter。但是
trait MyTrait {
def myStringVal: String
}
我实现此特性的case类如下所示:
case class MyCaseClass(myStringVal: String) extends MyTrait {
...
...
}
来自Java世界,我发现仅仅通过定义MyCaseClass的一个参数来理解MyCaseClass实际上实现了这一点有点困难。我知道你的字节码实际上会编写getter和setter。但是,没有任何var或val,这怎么可能呢
我的理解是,如果没有var或val,那么就不会生成getter或setter方法。在这种情况下,上面的case类MyCaseClass是如何实现myStringVal方法的
有时候,Scala的魔力太多了,特别是对于遗留代码,很难理解。Case类是不同的——会为它们生成一些默认方法。这包括参数的val getter。把case类想象成pojo——这是一个有用的语法糖,因为它们不需要私有成员
还生成了一些其他有用的方法,例如
copy
、toString
、apply
和unapply
Scala案例类为您实现了大量的样板文件,并且将所有构造函数参数自动公开为val
s就是其中之一
如果您尝试在常规类中避免使用val
s,如下所示:
trait MyTrait {
def myVal: String
}
class MyClass(myVal: String) extends MyTrait
编译器将向您显示错误消息,即MyClass必须是抽象的,因为它不会覆盖
myVal
方法,但将val
或var
添加到类构造函数参数将解决此问题。您可能希望查看哪些案例类以及它们为什么如此有用
在您的示例中,traitMyTrait
除了能够像java接口一样工作外,没有任何用处。请注意,scala中的默认可见性是公共的。默认情况下,case类参数是不可变的,因此在您的示例中,val
由编译器为myStringVal
参数自动推断
案例课有什么魔力
- 默认情况下,将所有构造函数参数转换为公共只读(
)val
- 使用每个方法的所有构造函数参数生成
、toString()
和equals()
方法hashcode()
- 生成同名的伴随对象,其中包含适当的
和apply()
方法,基本上,它只是一个方便的构造函数,允许在不使用unapply()
关键字的情况下实例化,并且是一个提取器,默认情况下,提取器会生成一个案例类参数的选项包装的new
tuple
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);
}
如果我为我的case类编写自己的同伴对象呢?我想这也是可以接受的?案例类可以扩展吗?我想这不是因为它们是不可变的,编写自己的伴奏对象应该可以,但是我个人会使用默认值作为参数。case类本身不是不可变的,我将使用类/case类的编译器输出更新我的答案。根本没有测试过从case类继承-您需要在父类型上进行模式匹配吗?我在这里不是专家——也许其他人可以进一步阐述?从traits(抽象)类等继承是可以的。但是,您需要在case类构造函数中指定父类的每个公共属性。给定的链接不起作用。因此,从archive.org获取: