{
class MyClass(name: String) {}
val x = new MyClass("x")
println(x.name) // Error name is not a member of MyClass
}
但
{
abstract class Base
case class MyClass(name: String) extends Base {}
var x = new MyClass("x")
println(x.name) // name is a member of MyClass
}
那么,案例类的处理是什么?为什么所有构造函数参数都变成了变量。
答案 0 :(得分:2)
name
在两个示例中都是成员,但在第一个示例中是私有的,而在第二个示例中是公开的。 Case类默认使用构造函数参数public val
。
答案 1 :(得分:2)
为了清楚起见,构造函数参数不用于创建变量,它们用于创建值。
如果您在第一个示例中指定val
,则为非案例类:
class MyClass(val name: String) {}
然后你也可以将参数翻译成公共值,与案例类相同。
在Scala-Lang site的示例中,它说:
如果使用模式匹配,仅定义案例类是有意义的 分解数据结构。以下对象定义了一个漂亮的 我们的lambda演算表示的打印机函数:
后跟示例代码:
object TermTest extends Application { def printTerm(term: Term) {
term match {
case Var(n) =>
print(n)
case Fun(x, b) =>
print("^" + x + ".")
printTerm(b)
case App(f, v) =>
Console.print("(")
printTerm(f)
print(" ")
printTerm(v)
print(")")
} } def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false } val id = Fun("x", Var("x")) val t = Fun("x", Fun("y", App(Var("x"), Var("y")))) printTerm(t) println println(isIdentityFun(id)) println(isIdentityFun(t)) }
答案 2 :(得分:2)
模式匹配是最重要但不是案例类的唯一应用程序。另一个重点是,它们根据构造函数参数(也称为产品元素)实现equals
和hashCode
方法。因此,案例类对于定义用作映射中的集合或键中的元素的数据结构非常有用。如果这些元素可见,那反过来才有意义。
比较
class Foo(val i: Int)
val set1 = Set(new Foo(33))
set1.contains(new Foo(33)) // false!!
和
case class Bar(val i: Int)
val set2 = Set(Bar(33)
set2.contains(Bar(33)) // true!
具有相同参数的两个案例类实例本身相同。你可以想象它们代表了一些“常量”。这意味着你不应该有可变状态。
但是,您可以使用第二个参数列表从等式中排除参数:
case class Baz(i: Int)(val n: Long)
Baz(33)(5L) == Baz(33)(6L) // true!
另一个有用的特性暗示构造函数参数成为值,正在制作副本。这是不可变数据更改的方式 - 您创建一个特定值已更改的新实例,保留原始值。
case class Person(name: String, age: Int)
val p1 = Person("Fuzzi", 33)
val p2 = p1.copy(age = 34)
复制方法使用所有未指定参数的默认值,从构造函数args中获取这些值。
答案 3 :(得分:1)
由于缺少可用空间而在评论中添加内容:请考虑以下示例案例类:
case class My(x: Int)
如果您将其保存到文件并将其传递给scalac -print
,您将获得以下扩展代码(我删除了不重要的内容):
case class My extends Object with Product with Serializable {
<caseaccessor> <paramaccessor> private[this] val x: Int = _;
<stable> <caseaccessor> <accessor> <paramaccessor> def x(): Int = My.this.x;
请注意<caseaccessor>
此处。
然后是伴侣对象:
<synthetic> object My extends runtime.AbstractFunction1 with Serializable {
case <synthetic> def apply(x: Int): My = new My(x);
case <synthetic> def unapply(x$0: My): Option = if (x$0.==(null))
scala.this.None
else
new Some(scala.Int.box(x$0.x()));
case <synthetic> <bridge> def apply(v1: Object): Object = My.this.apply(scala.Int.unbox(v1));
//...
请注意apply
和unapply
。如果您自己查看完整输出,您将了解有关scala如何生成代码的更多信息。