我在Google中搜索了case class
和class
之间的区别。 每一个人都提到,当您要在类上进行模式匹配时,请使用用例类。 不然,使用类,还说起一些额外的好处,例如equals和哈希码覆盖。 可是,这些是为何应该使用案例类而不是类的惟一缘由吗? app
我猜应该在Scala中使用此功能有一些很是重要的缘由。 有什么解释?是否有资源能够从中学习更多有关Scala案例类的信息? 函数
没有人提到案例类具备val
构造函数参数,但这也是常规类的默认值( 我认为这在Scala的设计中是不一致的)。 达里奥(Dario)在他指出它们“ 不可变 ”的地方暗示了这一点。 学习
请注意,您能够经过为案例类在每一个构造函数参数前添加var
来覆盖默认值。 可是,使案例类可变则会致使其equals
和hashCode
方法具备时变性。[1] 优化
sepp2k已经提到案例类自动生成equals
和hashCode
方法。 spa
也没有人提到案例类自动建立与该类同名的伴随object
,其中包含apply
和unapply
方法。 apply
方法能够构造实例,而无需添加new
。 在unapply
提取方法使图案匹配,其余人说起。 设计
另外,编译器还优化了match
速度-案例类的case
模式匹配[2]。 code
[1] 案例类别很酷 orm
[2] 案例分类和提取器,第15页 。 对象
案例类能够看做是普通且不可变的数据保存对象,应仅取决于其构造函数参数 。 继承
这个功能概念使咱们可以
Node(1, Leaf(2), None))
) 与继承结合使用,case类用于模拟代数数据类型 。
若是对象在内部执行状态计算或表现出其余复杂的行为,则应为普通类。
(您已经提到了除最后一个之外的全部内容)。
这些是普通班级的惟一区别。
从技术上讲,类和案例类之间没有区别-即便编译器在使用案例类时确实优化了某些内容。 可是,案例类用于取消特定模式的样板,该特定模式正在实现代数数据类型 。
这种类型的一个很是简单的例子是树。 例如,能够像这样实现一个二叉树:
sealed abstract class Tree case class Node(left: Tree, right: Tree) extends Tree case class Leaf[A](value: A) extends Tree case object EmptyLeaf extends Tree
这使咱们可以执行如下操做:
// DSL-like assignment: val treeA = Node(EmptyLeaf, Leaf(5)) val treeB = Node(Node(Leaf(2), Leaf(3)), Leaf(5)) // On Scala 2.8, modification through cloning: val treeC = treeA.copy(left = treeB.left) // Pretty printing: println("Tree A: "+treeA) println("Tree B: "+treeB) println("Tree C: "+treeC) // Comparison: println("Tree A == Tree B: %s" format (treeA == treeB).toString) println("Tree B == Tree C: %s" format (treeB == treeC).toString) // Pattern matching: treeA match { case Node(EmptyLeaf, right) => println("Can be reduced to "+right) case Node(left, EmptyLeaf) => println("Can be reduced to "+left) case _ => println(treeA+" cannot be reduced") } // Pattern matches can be safely done, because the compiler warns about // non-exaustive matches: def checkTree(t: Tree) = t match { case Node(EmptyLeaf, Node(left, right)) => // case Node(EmptyLeaf, Leaf(el)) => case Node(Node(left, right), EmptyLeaf) => case Node(Leaf(el), EmptyLeaf) => case Node(Node(l1, r1), Node(l2, r2)) => case Node(Leaf(e1), Leaf(e2)) => case Node(Node(left, right), Leaf(el)) => case Node(Leaf(el), Node(left, right)) => // case Node(EmptyLeaf, EmptyLeaf) => case Leaf(el) => case EmptyLeaf => }
请注意,树使用相同的语法构造和解构(经过模式匹配),这也正是它们的打印方式(减去空格)。
而且它们还能够与哈希映射或集一块儿使用,由于它们具备有效,稳定的hashCode。
Scala中的case类构造也能够看做是删除某些样板的便利。
在构造案例类时,Scala为您提供了如下内容。
apply
方法。 您将得到没必要使用new关键字的语法优点。
因为该类是不可变的,所以您将得到访问器,这些访问器仅是该类的变量(或属性),而没有变种器(所以没法更改变量)。 构造函数参数能够做为公共只读字段自动提供给您。 比Java bean构造好用得多。
hashCode
, equals
和toString
方法,而且equals
方法在结构上比较对象。 生成copy
方法以可以克隆对象(某些字段具备提供给该方法的新值)。 如前所述,最大的优点是您能够在案例类上进行模式匹配。 这样作的缘由是由于您得到了unapply
方法,该方法使您能够解构case类以提取其字段。
从本质上讲,在建立案例类(或案例对象,若是您的类不带参数)时从Scala得到的内容是单例对象,其目的是用做工厂和提取器 。