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,很抱歉延迟回复。提取器是一个稍微不同的动物,我不确定你是否需要一个只有你所示的小代码,但我刚刚更新了一个例子的答案,让你考虑。希望这有帮助!