Scala的案例类和类之间有什么区别?

我在Google中搜索了case classclass之间的区别。 每一个人都提到,当您要在类上进行模式匹配时,请使用用例类。 不然,使用类,还说起一些额外的好处,例如equals和哈希码覆盖。 可是,这些是为何应该使用案例类而不是类的惟一缘由吗? app

我猜应该在Scala中使用此功能有一些很是重要的缘由。 有什么解释?是否有资源能够从中学习更多有关Scala案例类的信息? 函数


#1楼

没有人提到案例类具备val构造函数参数,但这也是常规类的默认值( 我认为这在Scala的设计中是不一致的)。 达里奥(Dario)在他指出它们“ 不可变 ”的地方暗示了这一点。 学习

请注意,您能够经过为案例类在每一个构造函数参数前添加var来覆盖默认值。 可是,使案例类可变则会致使其equalshashCode方法具备时变性。[1] 优化

sepp2k已经提到案例类自动生成equalshashCode方法。 spa

也没有人提到案例类自动建立与该类同名的伴随object ,其中包含applyunapply方法。 apply方法能够构造实例,而无需添加new 。 在unapply提取方法使图案匹配,其余人说起。 设计

另外,编译器还优化了match速度-案例类的case模式匹配[2]。 code

[1] 案例类别很酷 orm

[2] 案例分类和提取器,第15页对象


#2楼

案例类能够看做是普通且不可变的数据保存对象,应仅取决于其构造函数参数继承

这个功能概念使咱们可以

  • 使用紧凑的初始化语法( Node(1, Leaf(2), None))
  • 使用模式匹配分解它们
  • 隐式定义相等比较

与继承结合使用,case类用于模拟代数数据类型

若是对象在内部执行状态计算或表现出其余复杂的行为,则应为普通类。


#3楼

  • 案例类能够进行模式匹配
  • 案例类自动定义哈希码并等于
  • 案例类自动为构造函数参数定义getter方法。

(您已经提到了除最后一个之外的全部内容)。

这些是普通班级的惟一区别。


#4楼

从技术上讲,类和案例类之间没有区别-即便编译器在使用案例类时确实优化了某些内容。 可是,案例类用于取消特定模式的样板,该特定模式正在实现代数数据类型

这种类型的一个很是简单的例子是树。 例如,能够像这样实现一个二叉树:

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。


#5楼

Scala中的case类构造也能够看做是删除某些样板的便利。

在构造案例类时,Scala为您提供了如下内容。

  • 它建立一个类及其伴随对象
  • 它的伴随对象实现了您能够用做工厂方法的apply方法。 您将得到没必要使用new关键字的语法优点。

因为该类是不可变的,所以您将得到访问器,这些访问器仅是该类的变量(或属性),而没有变种器(所以没法更改变量)。 构造函数参数能够做为公共只读字段自动提供给您。 比Java bean构造好用得多。

  • 默认状况下,您还得到hashCodeequalstoString方法,而且equals方法在结构上比较对象。 生成copy方法以可以克隆对象(某些字段具备提供给该方法的新值)。

如前所述,最大的优点是您能够在案例类上进行模式匹配。 这样作的缘由是由于您得到了unapply方法,该方法使您能够解构case类以提取其字段。


从本质上讲,在建立案例类(或案例对象,若是您的类不带参数)时从Scala得到的内容是单例对象,其目的是用做工厂提取器

相关文章
相关标签/搜索