Scala中使用TypeTag在类型层次结构上进行模式匹配的惯用方法是什么



我有一个类型层次结构,想要为实现请求一个查找方法。如果不求助于asInstanceOf呼叫,我很难做到这一点。

所以给出一个简单的类型层次结构,比如

trait Vehicle
trait Flying extends Vehicle
class Plane extends Flying
trait Driving extends Vehicle
class Car extends Driving
trait Swimming extends Vehicle
class Boat extends Swimming

我的查找方法是这样的

def findVehicle[V <: Vehicle](implicit tag: TypeTag[V]): Option[V] = {
  val v = tag.tpe match {
    case t if t =:= typeOf[Flying] => Some(new Plane)
    case t if t =:= typeOf[Driving] => Some(new Car)
    case t if t =:= typeOf[Swimming] => Some(new Boat)
    case _ => None
  }
  v.map(_.asInstanceOf[V])
}

使用类似的查找

println(findVehicle[Flying])  // Some(Plane@5b7fd935)

有可能在没有asInstanceOf的情况下实现这样的查找吗?

您可以避免使用TypeTag,而是使用类型类。

trait Builder[+T] {
  def build: Option[T]
}
implicit val flyingBuilder = new Builder[Flying] {
  def build = Some(new Plane)
}
implicit val drivingBuilder = new Builder[Driving] {
  def build = Some(new Car)
}
implicit val swimmingBuilder = new Builder[Swimming] {
  def build = Some(new Boat)
}
implicit val anyBuilder = new Builder[Nothing] {
  def build = None
}
def findVehicle[V <: Vehicle](implicit b: Builder[V]): Option[V] = b.build

不涉及反思,而且肯定更地道。

请注意,定义Builder[Nothing]如何重现通过返回None所实现的相同行为。这不一定是个好主意,因为您现在必须检查该方法是否能够产生值。

如果无法构建所需类型的实例,并且可以通过直接返回T而不是从build返回Option[T]来实现,那么我更希望出现编译时错误(当然也可以去掉Nothing的情况)。

最新更新