2017-06-27 43 views
0

我有一系列实例,其中每个实例都可以隐式转换为相同类型。 什么是转换这种序列的最佳方式?序列中的隐式转换

class A 
    class B 

    trait Resolver { 
    def resolve: String 
    } 

    implicit class AResolver(a: A) extends Resolver { 
    def resolve: String = "a" 
    } 
    implicit class BResolver(b: B) extends Resolver { 
    def resolve: String = "b" 
    } 

    def resolveThem(a: Option[A], b: Option[B]): Iterable[String] = { 
    val resolvers: Seq[Resolver] = a ++ b // type error 
    val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x: Resolver) => x} // empty 
    val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x: A) => x} // unexpectedly for me but it is also type error when there is an x:A 
    val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x: A) => x:Resolver} // works but returns only A as resolver 
    val resolvers: Seq[Resolver] = List(a, b).collect{case Some(x /*something that can be implicitly converted to Resolver*/) => x:Resolver} // Is it possible? 
    val resolvers: Seq[Resolver] = List(a.get, b.get) // this bad approach works 
    resolvers.map(_.resolve) // this is what I want as result 
    a.map(_.resolve) ++ b.map(_.resolve) // there is another way but if I have more arguments it becomes too long 
    } 
+1

这似乎是一个错误的隐式类的用法 – cchantep

回答

2
  1. 当确切类型可用于编译器,你只能使用implicits。只要您将对象放入简单的List中,其各个类型就会消失。 (尽管你可以使用HList。)
  2. 对于两个参数,你只需使用你的工作方法。
  3. 对于更多参数,您可能希望拥有带有一个参数的构建器。

    trait Builder { 
        def add[A: Resolver](a: A): Builder = { 
        use(a.resolve) 
        this 
        } 
    } 
    
  4. 如果有只有少数几类,你可以使用运行时的比赛:

    def getResolver(any: Any): Resolver = any match { 
        case a: A => a: Resolver 
        case b: B => b: Resolver 
        case _ => throw new IllegalArgumentException(s"$any is not supported" 
    } 
    

    然而,这种方法是非常非常糟糕。它不可扩展。

  5. 您也可以使用类型类而不是隐式转换。

    trait Resolvable[T] { 
        def resolve(a: T): String 
        } 
        implicit class AResolvable extends Resolvable[A] { 
        def resolve(a: A): String = "a" 
        } 
    

    这是我首选的方式。

0

方法collect接受PartialFunction[A, B],这意味着函数定义仅在可能的输入参数A和隐式转换的一个子集将不被应用。

转换应该明确或事先进行。为你的情况做一个这样做的方法是采取可变参数或序列的方法:

def resolveThem (resolvers: Option[Resolver]*): Iterable[String] = { 
    resolvers.flatten.map(_.resolve) 
} 

resolveThem(Option(new A), Option(new B))