2014-10-16 37 views
2

我有一个类型层次结构,并希望为实现请求查找方法。我在遇到问题时无需使用asInstanceOf电话。在Scala中用TypeTag对类型层次结构进行模式匹配的习惯用法是什么?

所以给人一种简单的类型层次结构,像这样

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([email protected]) 

查找是否有可能实现像这样的查找没有asInstanceOf在最后?

回答

2

您可以避免使用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来重现您实现的相同行为。这不一定是个好主意,因为你现在被迫检查该方法是否能够产生价值。

我宁愿一个编译时错误,如果它是不可能建立所需类型的实例,您可以通过直接返回Tbuild反对Option[T]实现它(当然摆脱Nothing箱子的) 。

+0

这看起来很有希望,但是如何处理'case _ => None'情况? – 2014-10-16 16:39:43

+0

为了使上面的注释更加清楚:如果'flyingBuilder'没有被定义,我们得到一个编译错误,而不是'findVehicle'的'None'结果 – 2014-10-16 17:43:04

+0

我更新了我的答案。既然'Builder'是协变的,你可以简单地用'build'来返回一个'Option [T]'并且在范围内有一个'Builder [Nothing]。 – 2014-10-16 19:30:35

相关问题