Case Class

下面会用到的 case 类实例:

case class Person(lastname: String, firstname: String, birthYear: Int)

基本特性

case 类与普通类的最大区别在于,编译器会为 case 类添加更多的额外特性。

  • 创建一个类和它的伴生对象

  • 创建一个名为apply的工厂方法。因此可以在创建实例时省略掉new关键字:

    val p = new Person("Lacava", "Alessandro", 1976)
    val p = Person("Lacava", "Alessandro", 1976)
    
  • 为参数列表中的所有参数添加val前缀,表示这些参数作为类的不可变成员,因此你会得到所有这个成员的访问器方法,而没有修改器方法:

    val lastname = p.lastname
    p.lastname = "Brown"		// 编译失败
    
  • hashCodeequalstoString方法添加原生实现。因为==在 Scala 中代表equals,因此 case 类实例之间总是以结构的方式进行比较,即比较数据而不是比较引用

    val p_1 = Person("Brown", "John", 1969)
    val p_2 = Person("Lacava", "Alessandro", 1976)
    
    p == p_1 // false
    p == p_2 // true
    
  • 生成一个copy方法,使用现有的实例并接收一些新的字段值来创建一个新的实例:

    val p_3 = p.copy(firstname = "Michele", birthYear = 1972)
    
  • 最重要的特性,实现一个 unapply 方法。因此,case 类可以支持模式匹配。这在定义 ADT 时尤为重要。unapply方法就是一个析构器

  • 当不需要参数列表时,可以定义为一个case object

常用其他特性

  • 创建一个函数,根据提供的参数创建一个 case 类的实例:

    val personCreator: (String, String, Int) => Person = Person.apply _
    personCreator("Brown", "John", 1969)	// Person(Brown,John,1969)
    
  • 如果需要将上面的函数柯里化分多步提供参数来创建一个实例:

    val curriedPerson: String => String => Int => Person = Person.curried
    
    val lacavaBuilder: String => Int => Person = curriedPerson("Lacava")
    
    val me = lacavaBuilder("Alessandro")(1976)
    val myBrother = lacavaBuilder("Michele")(1972)
    
  • 通过一个元组来创建实例:

    val tupledPerson: ((String, String, Int)) => Person = Person.tupled
    
    val meAsTuple: (String, String, Int) = ("Lacava", "Alessandro", 1976)
    
    val meAsPersonAgain: Person = tupledPerson(meAsTuple)
    
  • 将一个实例转换成一个由其参数构造的元组的Option

    val toOptionOfTuple: Person => Option[(String, String, Int)] = Person.unapply _
    
    val x: Option[(String, String, Int)] = toOptionOfTuple(p) // Some((Lacava,Alessandro,1976))
    

curriedtupled方法通过伴生对象继承自AbstractFunctionNN是参数的数量,如果N = 1则并不会得到这两个方法。

柯里化 的方式定义 case 类

Scala Case Classes In Depth

其他内建方法

因为所有的 case 类都会扩展Product特质,因此他们会得到如下方法:

  • def productArity:Int:获得参数的数量
  • def productElement(n:Int):Any:从 0 开始,获得第 n 个参数的值
  • def productIterator: Iterator[Any]:获得由所有参数构造的迭代器
  • def productPrefix: String:获得派生类中用于toString方法的字符串,这里会返回类名