从超类列表中提取给定子类的元素

问题描述

给定这个代码

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 :)