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

Extract element of given subclass from list of superclass

鉴于此代码

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(), new Pitbull(), 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 才能匹配 collectFirst 中的 A 类型。

当你写 Animal extends Identity 时,你的意思是 Animal IS an Identity,这是错误的,最好使用这种方法:

class Animal { self: Identity => 
}

这意味着无论何时你想实例化一个 Animal,你都需要给它一个 Identity,但你为什么要这样做呢? 您可以简单地使用模式匹配来过滤所需的类型,如下所示:

import scala.reflect.ClassTag
def getElementsOfType[A <: Animal : ClassTag](animals: List[Animal]): Option[A] = {
  animals.filter {
    case a: A => true
    case _ => false
  }.map(_.asInstanceOf[A]).headOption
}

headOption 是因为你的 api returns Option[A] 作为结果,你可以将它设为 return List[A] 并去掉 headOption 以防你有列表中有多个比特犬 :)