如何避免类型套管

时间:2012-10-04 17:41:11

标签: scala

注意:这是关于type-casing的问题,而不是类型转换。请停止更改标题。

我想编写一个泛型函数retrieve[F],它根据运行时指定的List[F]返回F

trait Foo
trait Bar extends Foo
trait Baz extends Foo

def retrieve[F <: Foo](implicit m: Manifest[F]): List[F] = m.erasure match {
  case x if x.isAssignableFrom(classOf[Bar]) => List[Bar]().asInstanceOf[List[F]]
  case x if x.isAssignableFrom(classOf[Baz]) => Nil
  case _ => Nil
}

是否有更安全的方式来执行此操作(即不使用清单isAssignableFrom,并将每个返回值转换为List[F])?

2 个答案:

答案 0 :(得分:0)

消除演员表的一种方法是使用存在类型:

trait Foo
trait Bar extends Foo
trait Baz extends Foo                                       

case object Bar1 extends Bar                                
case object Baz1 extends Baz                                

def retrieve[F <: Foo](implicit m: Manifest[F]): List[_ <: Foo] = m.erasure match {
  case x if x.isAssignableFrom(classOf[Bar]) => List[Bar]()  
  case x if x.isAssignableFrom(classOf[Baz]) => Nil  
  case _ => Nil
}           

不幸的是,似乎仍有一些类型信息丢失,因为在编译时不知道将返回Foo实现:

val foos: List[Foo] = retrieve[Bar]                         
// val bars: List[Bar] = retrieve[Bar] // does not compile

答案 1 :(得分:0)

我最终使用类型类实现了这个。不丢失类型信息,也不需要类型套管(或铸造型)。

我能看到的唯一奇怪的一点就是选择直接将retrieve移植到BarBaz类,但它似乎可以解决这个问题。

trait Foo
case class Bar(x: String) extends Foo
case class Baz(x: String) extends Foo

trait Retrievable[A] {
  def retrieve: List[A]
}

val _bars: List[Bar] = List(Bar("bar a"),Bar("bar b"))
val _bazs: List[Baz] = List(Baz("baz 1"),Baz("baz 2"))

implicit def barsRetrievable(x: Class[Bar]): Retrievable[Bar] =
  new Retrievable[Bar] {
    override def retrieve: List[Bar] = _bars
  }

implicit def foosRetrievable(x: Class[Baz]): Retrievable[Baz] =
  new Retrievable[Baz] {
    override def retrieve: List[Baz] = _bazs
  }

val bars: List[Bar] = classOf[Bar].retrieve
// bars: List(Bar(bar a), Bar(bar b))

val bazs: List[Baz] = classOf[Baz].retrieve
// bazs: List(Baz(baz 1), Baz(baz 2))