Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 从另一个案例类扩展案例类_Scala - Fatal编程技术网

Scala 从另一个案例类扩展案例类

Scala 从另一个案例类扩展案例类,scala,Scala,我有两个案例类人员和员工 我遇到以下错误: Unspecified value parameters: identifier: String Error: case class Employee has case ancestor Person, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes 我是

我有两个案例类人员和员工

我遇到以下错误:

Unspecified value parameters: identifier: String
Error: case class Employee has case ancestor Person, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes
我是Scala的新手,无法理解我必须做什么

版本:
Scala:2.11

不幸的是,case类恐怕无法扩展另一个case类

“普通”类中的继承如下所示:

class Person(val identifier: String) {}

class Employee(override val identifier: String, salary: Long)
  extends Person(identifier) {}

val el = new Employee("abc-test", 999)
println(el.identifier) // => "abc-test"
如果你想在
case
类中获得类似的效果,你需要接触
trait
s:

trait Identifiable {
  def identifier: String
}

case class Person(identifier: String) extends Identifiable {}

case class Employee(identifier: String, salary: Long)
  extends Identifiable {}

val el = Employee("abc-test", 999)
println(el.identifier) // => "abc-test"
定义提取器

提取器提供了一种定义模式匹配中使用的匹配语句的方法。它在
unapply
方法中的
对象中定义

让我们考虑第一个例子,再次添加提取器的支持:

class Person(val identifier: String)

class Employee(override val identifier: String, val salary: Long)
  extends Person(identifier)

object Person {
  def unapply(identifier: String): Option[Person] = {
    if (identifier.startsWith("PER-")) {
      Some(new Person(identifier))
    }
    else {
      None
    }
  }
}

object Employee {
  def unapply(identifier: String): Option[Employee] = {
    if (identifier.startsWith("EMP-")) {
      Some(new Employee(identifier, 999))
    }
    else {
      None
    }
  }
}
def process(anInput: String): Unit = {
  anInput match {
    case Employee(anEmployee) => println(s"Employee identified ${anEmployee.identifier}, $$${anEmployee.salary}")
    case Person(aPerson) => println(s"Person identified ${aPerson.identifier}")
    case _ => println("Was unable to identify anyone...")
  }
}

process("PER-123-test") // => Person identified PER-123-test
process("EMP-321-test") // => Employee identified EMP-321-test, $999
process("Foo-Bar-Test") // => Was unable to identify anyone...
现在,让我们定义一个方法,该方法将使用这些提取器定义模式匹配:

class Person(val identifier: String)

class Employee(override val identifier: String, val salary: Long)
  extends Person(identifier)

object Person {
  def unapply(identifier: String): Option[Person] = {
    if (identifier.startsWith("PER-")) {
      Some(new Person(identifier))
    }
    else {
      None
    }
  }
}

object Employee {
  def unapply(identifier: String): Option[Employee] = {
    if (identifier.startsWith("EMP-")) {
      Some(new Employee(identifier, 999))
    }
    else {
      None
    }
  }
}
def process(anInput: String): Unit = {
  anInput match {
    case Employee(anEmployee) => println(s"Employee identified ${anEmployee.identifier}, $$${anEmployee.salary}")
    case Person(aPerson) => println(s"Person identified ${aPerson.identifier}")
    case _ => println("Was unable to identify anyone...")
  }
}

process("PER-123-test") // => Person identified PER-123-test
process("EMP-321-test") // => Employee identified EMP-321-test, $999
process("Foo-Bar-Test") // => Was unable to identify anyone...

从case类继承(即使是不禁止的常规非case类)也是一个坏主意。查看以了解原因

您不需要是案例类。它实际上根本不需要是一个类:

trait Person {
   def identifier: String
}
case class Employee(identifier: String, salary: Long) extends Person

Scala中的Case类添加了几个不同的特性,但通常您只使用其中的一部分。因此,您需要回答的主要问题是您真正需要哪些功能。以下是基于以下内容的列表:

  • 不需要在字段名/构造函数参数之前键入
    val
  • 通过向伴随对象添加
    apply
    方法,消除对
    new
    的需要
  • 通过向伴随对象添加
    方法来支持模式匹配。(Scala的一个优点是模式匹配是以一种非魔法的方式完成的,您可以为任何数据类型实现它,而不需要它是
    案例类
  • 根据所有字段添加
    equals
    hashCode
    实现
  • 添加
    toString
    实现
  • 添加
    copy
    方法(很有用,因为
    case类在默认情况下是不可变的)
  • 实施
    产品
    特性
案例类人物(标识符:字符串)
的等价物的合理猜测如下

class Person(val identifier: String) extends Product  {

  def canEqual(other: Any): Boolean = other.isInstanceOf[Person]

  override def equals(other: Any): Boolean = other match {
    case that: Person => (that canEqual this) && identifier == that.identifier
    case _ => false
  }

  override def hashCode(): Int = identifier.hashCode

  override def toString = s"Person($identifier)"

  def copy(newIdentifier: String): Person = new Person(newIdentifier)

  override def productElement(n: Int): Any = n match {
    case 0 => identifier
    case _ => throw new IndexOutOfBoundsException(s"Index $n is out of range")
  }

  override def productArity: Int = 1
}

object Person {
  def apply(identifier: String): Person = new Person(identifier)

  def unapply(person: Person): Option[String] = if (person eq null) None else Some(person.identifier)
}

case class Employee(override val identifier: String, salary: Long) extends Person(identifier) {}

实际上,继承一个
案例类
尤其是使一个
案例类
继承另一个案例类的主要反对理由是
产品
特性、
复制
等于
/
哈希代码
,因为它们引入了歧义。添加
canEqual
可以部分缓解最后一个问题,但不能缓解第一个问题。另一方面,在像您这样的层次结构中,您可能根本不需要
copy
方法或
Product
实现。如果在模式匹配中不使用
Person
,也不需要不应用
。最有可能的是,你真正需要的
案例
就是
apply
toString
hashCode
/
等于
/
canEqual

实现什么?这是什么语言?@MahmoudHanafy我已经更正了声明错误消息告诉你“案例到案例”类是禁止的,所以你必须改变类的人,读一下:@user811602你写的“无法理解我必须做什么”。从你的问题来看,你不清楚你想要实现什么。很可能您希望从一个类派生另一个类,但这是:1)不能为case类完成(因为case类组合优于继承)2)使用稍微不同的语法完成(您需要将参数传递给基类构造函数)。我认为任何基本的Scala教程都会教你这一点,比在这里提问更方便。示例几乎与你在Alvin Alexander的Scala Cookbook中尝试做的相同:有一个错误陈述“为了克服这个限制,使用提取器在非叶节点上进行模式匹配”。这和你提到的是同一件事吗?嘿@user811602,很抱歉延迟回复。提取器是一个稍微不同的动物,我不确定你是否需要一个只有你所示的小代码,但我刚刚更新了一个例子的答案,让你考虑。希望这有帮助!