具有共同特征的模式匹配案例 类
Pattern Matching Case Classes with Common Trait
我正在编写一些使用模式匹配的代码。在测试中我发现了一个奇怪的结果:
object Example extends App {
trait Human {
def sing(): Unit
}
case class Son(name: String) extends Human {
override def sing(): Unit = println("son " + name)
}
case class Daughter(name: String) extends Human {
override def sing(): Unit = println("daughter " + name)
}
val jack = Son("jack")
val sonia = Daughter("sonia")
def f1(lst: List[Human]) = {
lst match {
case a: List[Son] => println("human is son")
case b: List[Daughter] => println("human is daughter")
}
}
f1(List(jack))
f1(List(sonia))
}
这两个都打印“human is a son”。有没有解决的办法?我可以看到编译器将 Son 和 Daughter 与 Human 匹配。但是有没有办法让它区分这两者呢?
重构代码以摆脱 List[Human] 修复了这个问题。
我们观察到,在这种特定情况下,我们可以简单地提取列表的第一个元素,而不是对列表进行操作。
看来您确实需要重构您的设计。你不应该需要在运行时检查列表中的类型元素——如果你想要动态调度,你可以有一个重写的方法,或者你可以为 List[Son]
s 和 List[Daughter]
.[= 使用单独的方法19=]
如果您真的想要确保列表中的所有元素都是sons/daughters,您可以使用forall
def f1(lst: List[Human]) =
if (lst.forall(_.isInstanceOf[Son])) println("human is son")
else if (lst.forall(_.isInstanceOf[Daughter])) println("human is daughter")
不过这不是很好。如果列表中有儿子 和 女儿,或者可能完全是第三种类型怎么办?
我推荐 2 种不同的方法 - 一种用于 Son
s,一种用于 Daughter
s。我还会将您的 Human
特征密封,这样就无需处理新的实现。
def f1(lst: List[Daughter]) = println("human is daughter")
//DummyImplicit is a workaround for type erasure, otherwise, they'd have the same signature
def f1(lst: List[Son])(implicit d: DummyImplicit) = println("human is son")
您也可以使用类型类,尽管在这里似乎不值得
def f1[A <: Human](lst: List[A])(implicit idr: Identifier[A]) =
idr.identify(lst)
sealed trait Identifier[A <: Human] {
def identify(lst: List[A]): String
}
object Identifier {
implicit val sonIdentifier: Identifier[Son] = _ => "human is son"
implicit val daughterIdentifier: Identifier[Daughter] = _ => "human is daughter"
}
我正在编写一些使用模式匹配的代码。在测试中我发现了一个奇怪的结果:
object Example extends App {
trait Human {
def sing(): Unit
}
case class Son(name: String) extends Human {
override def sing(): Unit = println("son " + name)
}
case class Daughter(name: String) extends Human {
override def sing(): Unit = println("daughter " + name)
}
val jack = Son("jack")
val sonia = Daughter("sonia")
def f1(lst: List[Human]) = {
lst match {
case a: List[Son] => println("human is son")
case b: List[Daughter] => println("human is daughter")
}
}
f1(List(jack))
f1(List(sonia))
}
这两个都打印“human is a son”。有没有解决的办法?我可以看到编译器将 Son 和 Daughter 与 Human 匹配。但是有没有办法让它区分这两者呢?
重构代码以摆脱 List[Human] 修复了这个问题。
我们观察到,在这种特定情况下,我们可以简单地提取列表的第一个元素,而不是对列表进行操作。
看来您确实需要重构您的设计。你不应该需要在运行时检查列表中的类型元素——如果你想要动态调度,你可以有一个重写的方法,或者你可以为 List[Son]
s 和 List[Daughter]
.[= 使用单独的方法19=]
如果您真的想要确保列表中的所有元素都是sons/daughters,您可以使用forall
def f1(lst: List[Human]) =
if (lst.forall(_.isInstanceOf[Son])) println("human is son")
else if (lst.forall(_.isInstanceOf[Daughter])) println("human is daughter")
不过这不是很好。如果列表中有儿子 和 女儿,或者可能完全是第三种类型怎么办?
我推荐 2 种不同的方法 - 一种用于 Son
s,一种用于 Daughter
s。我还会将您的 Human
特征密封,这样就无需处理新的实现。
def f1(lst: List[Daughter]) = println("human is daughter")
//DummyImplicit is a workaround for type erasure, otherwise, they'd have the same signature
def f1(lst: List[Son])(implicit d: DummyImplicit) = println("human is son")
您也可以使用类型类,尽管在这里似乎不值得
def f1[A <: Human](lst: List[A])(implicit idr: Identifier[A]) =
idr.identify(lst)
sealed trait Identifier[A <: Human] {
def identify(lst: List[A]): String
}
object Identifier {
implicit val sonIdentifier: Identifier[Son] = _ => "human is son"
implicit val daughterIdentifier: Identifier[Daughter] = _ => "human is daughter"
}