2016-05-23 66 views
1

我有一个总和类型,映射:我有一个类型类定义如下Scala的类型类复合材料

sealed trait Mapping 
final case class XMapping(a:String) 
final case class FallbackMapping(mappings: List[Mapping]) 

final case class Param(x:String) 

trait ParameterLoader[T] { 
    def load(mapping:T) : List[Param] 
} 

随着一些实例:

object DefaultParameterLoaders { 
    implicit val xParameterLoader= new QueryParameterLoader[XMapping] { 
    override def load(mapping: XMapping): List[Param] = List(Param(mapping.a)) 
    } 

    implicit val fallbackParameterLoader = new ParameterLoader[FallbackMapping] { 

    override def load(mapping: FallbackMapping): List[Param] = 
     mapping.mappings.flatMap(x => ???) 

    } 
} 

我可以找不到将隐式实例传递给上面的flatMap的方法。我得到的错误是我缺少一个ParameterLoader [Mapping]的实例。是否有某种方式告诉编译器它应该使用范围内的任何类型实例?

回答

2

该类型系统特别寻找ParameterLoader[Mapping],这意味着ParameterLoader[XMapping]/ParameterLoader[FallbackMapping]不够具体。您需要提供ParameterLoader[Mapping]。你可以使用你现有的定义来做到这一点。

implicit def mappingLoader(implicit xpLoader: ParameterLoader[XMapping], fmLoader: ParameterLoader[FallbackMapping]) = new ParameterLoader[Mapping] { 
    def load(mapping: Mapping): List[QueryParam] = 
    mapping match { 
     case xm: XMapping = xpLoader.load(xm) 
     case fm: FallbackMapping => fmLoader.load(fm) 
    } 
} 

另外,有你flatmap进行匹配逻辑:

implicit def fallbackParameterLoader(implicit xpLoader: ParameterLoader[XMapping]) = new ParameterLoader[FallbackMapping] { 
    override def load(mapping: FallbackMapping): List[Param] = 
    mapping.mappings.flatMap { 
     case xm: XMapping = xpLoader.load(xm) 
     case fm: FallbackMapping => this.load(fm) 
    } 
    } 
+0

感谢。这样可行。我希望以某种方式自动执行此操作。这锁定了所使用的实例,而理想情况下,我想使用客户端在范围内的任何实例。那可能吗? – ashic

+0

是的。不要像我那样显式地指定参数加载器,而是使用'implicitly [ParameterLoader [XMapping]] .load(xm)'来代替'xParameterLoader.load(xm)'。但是,这将使用构建时参数加载器的参数加载器。 – JBarber

+0

我已更新我的答案以支持您的使用案例。这将根据您在范围内的任何参数加载器派生一个mappingLoader。请记住,有这样的派生,行为可能会混淆,因为进口可以改变行为。确保这是有记录的,并让你的团队意识到它的工作原理。 – JBarber