• case class inheritance


    Scala 禁止case class inheritance

    case class Person(name: String, age: Int)
    case class FootballPlayer(name: String, age: Int, number: Int) extends Person(name, age)

    在编译时会报出以下错误:

    Error:(5, 12) case class FootballPlayer has case ancestor Person, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes.
    case class FootballPlayer(name: String, age: Int, number: Int) extends Person(name, age)
    ^

    原因有挺多,下边的两篇文章讲了下理由,但我还是没明白其中的必要性。

    http://tech.schmitztech.com/scala/caseclassinheritence.html

    http://stackoverflow.com/questions/11158929/what-is-so-wrong-with-case-class-inheritance


    我们可以使得两个case class继承同一个trait来实际于case class继承的行为,但是这样就得自己写extractor了。比如

      sealed trait Person{
        def age: Int
        def name: String
      }
      case class FootballPlayer(name: String, age: Int, number: Int) extends Person
      val torres = FootballPlayer("Fernando Torres", 31, 19)
      val Person(name, age) = torres // can't resolve symbal Person

    会编译出错, 因为Person是个trait,它并不支持extractor的语法。

    需要给Person加个Companion object,像这样

      object Person{
        def unapply(p: Person) = Some((p.name, p.age))
      }

    这时就能用extractor了

      val torres = FootballPlayer("Fernando Torres", 31, 19)
      val Person(name, age) = torres

    编译器会为case class生成equals方法,但普通类就不会了。

      sealed trait Person{
        def age: Int
        def name: String
      }
    
      case class FootballPlayer(name: String, age: Int, number: Int) extends Person
      class Doctor(val name: String, val age: Int) extends Person
      val torresA = FootballPlayer("Fernando Torres", 31, 19)
      val torresB = FootballPlayer("Fernando Torres", 31, 19)
      println(torresA == torresB)//true
    
      val docA = new Doctor("C", 30)
      val docB = new Doctor("C", 30)
      println(docA == docB)//false

    这时,当两个FootballPlayer的构造参数相同,它们就相等。但是对于Doctor类来说不是这样了。

    当给FootballPlayer这个case class的父类Person定义了equals方法之后,就不是这样了。

     sealed trait Person{self =>
        def age: Int
        def name: String
        override def equals(that: Any):Boolean = {
          that match{
            case p: Person => p.age == self.age && p.name == self.name
            case _ => false
          }
        }
        override def hashCode: Int = {
          var hash = 1
          hash = hash * 31 + age
          hash = hash * 31 + {if(name !=null) name.hashCode else 0}
          hash
        }
      }
      case class FootballPlayer(name: String, age: Int, number: Int) extends Person
      class Doctor(val name: String, val age: Int) extends Person
      val torresA = FootballPlayer("Fernando Torres", 31, 19)
      val torresB = FootballPlayer("Fernando Torres", 31, 19)
      torresA.equals(torresB)
      println(torresA == torresB)//true
    
      val docA = new Doctor("C", 30)
      val docB = new Doctor("C", 30)
      println(docA == docB) //true
    
      val footballPlayerC = FootballPlayer("C", 30, 30)
      println(footballPlayerC == docA) //true
      println(footballPlayerC.hashCode())//1958
      println(docA.hashCode())//1958

    貌似这时候case class就不会生成equals方法了, 转而使用父类Person的equals方法。并且要记得同时在Person中覆盖hashCode方法,不然就破坏了equals对hashCode的要求。

  • 相关阅读:
    代理模式之动态代理
    代理模式之静态代理
    基于Java类进行配置Spring
    Spring使用注解开发
    Spring的自动装配
    Bean的作用域
    Spring配置
    最全总结 | 聊聊 Python 办公自动化之 Excel(上)
    最全总结 | 聊聊 Python 数据处理全家桶(MongoDB 篇)
    最全总结 | 聊聊 Python 数据处理全家桶(Redis篇)
  • 原文地址:https://www.cnblogs.com/devos/p/4451935.html
Copyright © 2020-2023  润新知