How to get the correct return type when using a type-based filter in Scala

The following does not compile. Do I need to pour a person first?

 object People {
  def all = List(
    new Person("Jack", 33),
    new Person("John", 31) with Authority,
    new Person("Jill", 21),
    new Person("Mark", 43)
  )
}

class Person(val name: String, val age: Int) 

trait Authority {
  def giveOrder {
    println("do your work!")
  }
}

object Runner {
  def main(args:List[String]) {
    val boss = People.all.find { _.isInstanceOf [Authority] }.get
    boss.giveOrder // This line doesnt compile
  }
}
+3
source share
4 answers

You are right in thinking that somehow there must be a mechanism to avoid casting. Such a cast would be ugly and redundant, since it still appears in the filter. findhowever, it does not at all care about the form of the predicate that it receives; it just applies it and returns Option[A]if it Ais a static type of collection items.

You need a function collect:

val boss = People.all.collect { case boss: Authority => boss }.head

collect . ( , Authority) , view, :

val boss = People.all.view.collect { case boss: Authority => boss }.head

, , , , , . :

val bossOpt = People.all.view.collect { case boss: Authority => boss }.headOption
bossOpt.foreach(_.giveOrder) // happens only if a boss was found

: , Scala 2.9, collectFirst, .

+7

- , ...

Scala 2.9, collectFirst, view, head headOption

val boss = People.all.collectFirst { case x: Authority => x }
boss.foreach(_.giveOrder) // happens only if a boss was found

boss - Option[Person], . , , :

for(boss <- People.all.collectFirst { case x: Authority => x }) {
  boss.giveOrder // happens only if a boss was found
}
+5

try it

boss.asInstanceOf[Authority].giveOrder

or

val boss =  People.all.find { _.isInstanceOf [Authority] }.get.asInstanceOf[Person with Authority]
0
source

Do you really want to find only the first? finddoes just that. Consider using a solution from Jean-Philippe if you want to find all Authoritys:

val authorities = People.all.collect {
  case boss: Authority => boss
}.foreach(_.giveOrder)
0
source

All Articles