例如,我的代码如下所示:
class Parent
class Child1 extends Parent
class Child2 extends Parent
class Foo {
def retrieve(arg: String): List[Parent] = {
arg match {
case "Child1" => get[Child1]()
case "Child2" => get[Child2]()
}
}
def get[T: Manifest](): List[T] = ...
}
在retrieve
方法中,我想将代码简化为一个get
方法调用,如下所示:
def retrieve(arg: String): List[Parent] = {
val t = arg match {
case "Child1" => ?
case "Child2" => ?
}
get[t]()
}
是否有可能在scala中实现这一目标?
更新
我从这里的答案中尝试了解决方案,但我遇到了问题,它不适用于重载的get
方法,例如:
def get[T: Manifest](x: String): List[T] = ...
def get[T: Manifest, U: Manifest](x: String): List[(T, U)] = ...
例如,在retrieve
:
val t = arg match {
case "Child1" => manifest[Child1]
case "Child2" => manifest[Child2]
}
get("test")(t)
我在ambiguous reference to overloaded definition
行上遇到get("test")(t)
编译错误。
答案 0 :(得分:3)
您的问题归结为如何检索给定类型的Manifest
。这可以使用manifest
方法完成。然后你可以明确地将清单传递给get
。
class Foo {
def retrieve(arg: String): List[Parent] = {
val t = arg match {
case "Child1" => manifest[Child1]
case "Child2" => manifest[Child2]
}
get(t)
}
def get[T <: Parent: Manifest]: List[T] = ...
}
作为旁注,您应该使用地图来检索清单(而不是模式匹配),以便更容易编辑,或者可能在某一点上用一些init替换硬编码的类型列表时间计算:
object Foo {
private val manifestByName = Map[String, Manifest[_<:Parent]](
"Child1" -> manifest[Child1],
"Child2" -> manifest[Child2]
)
}
class Foo {
def retrieve(arg: String): List[Parent] = {
val t = Foo.manifestByName.getOrElse(arg, sys.error(s"Invalid class name $arg"))
get(t)
}
def get[T <: Parent: Manifest]: List[T] = { println(manifest[T]); Nil }
}
最后请注意,Manifest
现已弃用,已被ClassTag
\ TypeTag
取代。
答案 1 :(得分:2)
Manifest
基本上是deprecated。 :
在Scala 2.10中,不推荐使用scala.reflect.ClassManifests,它是 计划弃用scala.reflect.Manifest以支持TypeTags和 ClassTags将在即将发布的版本中发布。因此,建议 迁移任何基于Manifest的API以使用Tags。
您应该考虑使用更现代的ClassTag
或TypeTag
。在这种情况下,ClassTag
效果更好(因为TypeTags
不能用于模式匹配):
def retrieve(arg: String): List[Parent] = {
val t = arg match {
case "Child1" => classTag[Child1]
case "Child2" => classTag[Child2]
}
get(t)
}
def get[T : ClassTag]: List[T] = list collect {
case x: T => x
}
您可以在文档here中详细了解ClassTags
,TypeTags
及其与Manifest
的关系。
如果不清楚,这是有效的,因为T
上的类型约束是上下文绑定,这意味着get
的方法签名等同于:
def get[T](implicit ev: ClassTag[T]): List[T]
因此,当我们调用get(t)
时,我们明确指定隐式参数。阅读有关上下文边界here的更多信息。
如果上下文绑定或隐式参数混乱,您还可以通过使get
非泛型来实现目标:
def get(c: ClassTag[_]) = list collect {
case x if ClassTag(x.getClass) == c => x
}
这种非通用的非隐式版本可能会帮助您解决重载问题。