序列中的隐式转换

  • 本文关键字:转换 scala implicit
  • 更新时间 :
  • 英文 :


i具有一系列实例,每个实例都可以隐式转换为同一类型。转换此类序列的最佳方法是什么?

  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. 您只能在编译器可用的确切类型时使用隐式。一旦将对象放入简单的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"
      }
    

    我想这是首选的方式。

方法collect接受PartialFunction[A, B],这意味着该函数仅在可能的输入参数的子集A的子集上定义,并且不会应用隐式转换。

应明确或事先进行转换。为您的情况做到这一点的一种方法是采用varargs或序列的方法:

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

相关内容

  • 没有找到相关文章

最新更新