zoukankan      html  css  js  c++  java
  • 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的要求。

  • 相关阅读:
    解析大型.NET ERP系统 权限模块设计与实现
    Enterprise Solution 开源项目资源汇总 Visual Studio Online 源代码托管 企业管理软件开发框架
    解析大型.NET ERP系统 单据编码功能实现
    解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计
    Windows 10 部署Enterprise Solution 5.5
    解析大型.NET ERP系统 设计异常处理模块
    解析大型.NET ERP系统 业务逻辑设计与实现
    解析大型.NET ERP系统 多国语言实现
    Enterprise Solution 管理软件开发框架流程实战
    解析大型.NET ERP系统 数据审计功能
  • 原文地址:https://www.cnblogs.com/devos/p/4451935.html
Copyright © 2011-2022 走看看