删除类型时如何使用功能?

时间:2017-02-14 16:12:58

标签: scala type-erasure dynamic-cast

我需要通过界面传递函数,该界面会删除类似actor' s receive方法的类型。所以我想存储已擦除的类型参数并使用它来构建参数。

class Store[R,T](val action : R => T)(implicit i : TypeTag[R], o : TypeTag[T]) {
  val in : Type = i.tpe
  val out : Type = o.tpe
}
object Store {
  type Any = Store[_,_]
  def apply[R,T](action : R => T)(implicit i : TypeTag[R], o : TypeTag[T]) : Store[R,T] = new Store(action)
}

final case class Box[T](unbox : T)

def getType[T](x : T)(implicit t : TypeTag[T]) : Type = t.tpe

val source = Box("test")

val x = Store[Box[String], Box[Int]](s => Box(s.unbox.length))
val y = Store[Box[Int], Box[Boolean]](i => Box(i.unbox % 3 == 0))

val all : List[Store.Any] = List(x,y)
val a0 = all(0)
val a1 = all(1)

我希望将存储的操作链接起来:

val c0 = a0.action(source)
val c1 = a1.action(c0)

显然失败了:

error: type mismatch;
 found   : source.type (with underlying type Box[String])
 required: _$1
  val c0 = a0.action(source)
                     ^
one error found

我可以在运行时检查所有类型是否匹配:

assert(getType(source) <:< a0.in)
assert(a0.out <:< a1.in)

但是我怎样才能将参数转换为适当的类型呢? asInstanceOf需要编译时类型,而不是运行时反射。还有哪些其他技巧?

1 个答案:

答案 0 :(得分:1)

一种方法是使用ClassTag[T]及其unapply方法:

def castIfPossible[T](object: Any)(implicit tag: ClassTag[T]): Option[T] =
  tag.unapply(object)

如果object属于T类型,则会收到Some[T]值,否则您将收到None

然后,您需要在代码中执行的操作是假设类型始终匹配(但之后您可能不需要反射)或使用某些map或{ {1}}用于将值组合在一起。

就个人而言,我会试着弄清楚是否可以完全取消反射,好像T会被参数化,然后反射不会检查这些参数是否匹配。然后我会使用类型类来处理问题。但是,我知道它可能并不总是可能的。