以下内容无法编译。我需要先安排这个人吗?
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
}
}
答案 0 :(得分:7)
你是对的,不知何故,应该有一种机制可以让你避免施法。这样的演员阵容将是丑陋和多余的,因为它无论如何已经出现在过滤器中。然而,find
并不关心它所获得的谓词的形状;如果Option[A]
是集合元素的静态类型,它只应用它并返回A
。
您需要的是collect
功能:
val boss = People.all.collect { case boss: Authority => boss }.head
collect
创建一个新集合。如果你想避免这种情况(如果你真的只对第一个属于Authority
的元素感兴趣的话),如果有可能很长的潜在老板列表,你可能想要切换到{{1让它懒惰地评估:
view
最后,除非你绝对确定列表中至少有一个boss,否则你应该真正测试搜索是否成功,例如像这样:
val boss = People.all.view.collect { case boss: Authority => boss }.head
修改:最后,如果您使用的是Scala 2.9,则绝对应该按照Kevin Wright's answer中的说明使用val bossOpt = People.all.view.collect { case boss: Authority => boss }.headOption
bossOpt.foreach(_.giveOrder) // happens only if a boss was found
。
答案 1 :(得分:5)
Jean-Philippe的回答很好,但可以更进一步......
如果使用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-comprehension,有些人仍然更清洁:
for(boss <- People.all.collectFirst { case x: Authority => x }) {
boss.giveOrder // happens only if a boss was found
}
答案 2 :(得分:0)
试试这个
boss.asInstanceOf[Authority].giveOrder
或者
val boss = People.all.find { _.isInstanceOf [Authority] }.get.asInstanceOf[Person with Authority]
答案 3 :(得分:0)
你真的想找到第一个吗? find
就是这样做的。如果您想查找所有Authority
s:
val authorities = People.all.collect {
case boss: Authority => boss
}.foreach(_.giveOrder)