问题描述
给定这个代码
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
class Pitbull extends Dog{}
object MyClass {
def main(args: Array[String]) {
val animals: List[Animal] = List(new Dog(),new Cat(),new Pitbull(),new Dog(),new Cat())
getElementOftype(animals,PitBull)
}
def getElementOftype(list: List[Animal],givenType: ???): Animal = {
}
}
我想从此列表中提取 Pitbull 类型的第一个元素,我应该如何处理?
我尝试过但感觉不对
trait Identity{
def who: String
}
class Animal extends Identity{
override def who = "Animal"
}
class Dog extends Animal with Identity{
override def who = "Dog"
}
class Cat extends Animal with Identity{
override def who = "Cat"
}
class Pitbull extends Dog with Identity{
override def who = "Pitbull"
}
object MyClass {
def main(args: Array[String]) {
val animals: List[Animal] = List(new Dog(),new Cat())
println(getElementOftype(animals,new Pitbull()))
}
def getElementOftype(list: List[Animal],givenType: Animal): Option[Animal] = {
list.collectFirst{case s if s.who == givenType.who => s}
}
}
我想简单地将 Pitbull
作为参数传递,而不是实例化一个空对象。
这个方法可行,但我认为这不是最好的方法。 必须有一种更大规模的方式来做到这一点。
解决方法
你可以这样做(未测试,可能有一些错别字):
def getElementOftype[A <: Animal](list: List[Animal])(implicit ct: ClassTag[A]): Option[A] = {
list.collectFirst { case s: A => s }
}
必须使用 ClassTag
才能匹配 A
中的 collectFirst
类型。
当你写 target
时,你的意思是动物是一个身份,这是错误的,使用这种方法是首选:
Animal extends Identity
这意味着无论何时你想实例化一个动物,你都需要给它一个身份,但你为什么要这样做呢? 您可以简单地使用模式匹配来过滤所需的类型,如下所示:
class Animal { self: Identity =>
}
headOption 是因为你的 api 返回 Option[A] 作为结果,你可以让它返回 List[A] 并去掉 headOption,以防列表中有多个 Pitbull :)