在 Scala 中使用基于类型的过滤器时如何获取正确的返回类型
以下内容无法编译。我需要先选人物吗?
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
}
}
The following doesn't compile. Do I need to cast the 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
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的想法是对的,应该有一种机制可以让您避免强制转换。这样的强制转换将是丑陋且多余的,因为它已经出现在过滤器中了。然而,
find
根本不关心它得到的谓词的形状。如果A
是集合元素的静态类型,它只是应用它并返回一个Option[A]
。您需要的是
collect
函数:collect
创建一个新集合。如果您想避免这种情况(如果您确实只对第一个类型为Authority
的元素感兴趣),以防潜在老板列表可能很长,您可能需要切换到view
以延迟评估:最后,除非您完全确定列表中始终至少有一个老板,否则您应该真正测试搜索是否成功,例如如下所示:
编辑:最后,如果您使用的是 Scala 2.9,则绝对应该使用
collectFirst
,如 Kevin Wright 的回答。You're right thinking that somehow, there should be a mechanism that lets you avoid casting. Such a cast would be ugly and redundant, as it already appears in the filter anyway.
find
, however, does not care at all about the shape of the predicate it gets; it just applies it and returns anOption[A]
ifA
is the static type of the collection's elements.What you need is the
collect
function:collect
creates a new collection. If you want to avoid this (if you're really only interested in the first element which is of kindAuthority
) in case of a potentially very long list of potential bosses, you may want to switch to aview
to have it evaluated lazily:Finally, unless you're absolutely sure that there is always at least one boss in your list, you should really test whether or not the search was successful, e.g. like this:
Edit: Finally, if you're using Scala 2.9, you should definitely use
collectFirst
as explained in Kevin Wright's answer.Jean-Philippe 的答案很好,但还可以更进一步...
如果使用 Scala 2.9,您还将有一个可用的
collectFirst
方法,让您避免所有那些繁琐的view
、head
和headOption
的boss
仍然是Option[Person]
,为了代码更安全,我建议您保持这种方式。如果你愿意,你也可以使用 for-compression,有些人更清楚:Jean-Philippe's answer is good, but it's possible to go one step further...
If using Scala 2.9, you'll also have a
collectFirst
method available, allowing you to avoid all those tediousview
's,head
's andheadOption
'sboss
is still anOption[Person]
, I recommend that you keep it this way for the sake of safer code. If you want, you can also use a for-comprehension, which some people to be cleaner still:试试这个
或这个
Try this
or this
您真的只想找到第一个吗?
find
正是这样做的。如果您想查找所有Authority
,请考虑使用 Jean-Philippe 的解决方案:Do you really want to find just the first one?
find
does exactly this. Consider using the solution from Jean-Philippe if you want to find allAuthority
s: