序列内的隐式转换
Implicit convertion within a sequence
我有一个实例序列,其中每个实例都可以隐式转换为同一类型。
转换这种序列的最佳方法是什么?
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
}
- 您只能在编译器可以使用精确类型时使用隐式。一旦将对象放入简单的
List
中,它们各自的类型就会消失。 (不过你可以使用 HList
。)
- 对于两个参数,您只需使用您的工作方法即可。
要获得更多参数,您可能需要一个只有一个参数的构建器。
trait Builder {
def add[A: Resolver](a: A): Builder = {
use(a.resolve)
this
}
}
如果只有几个类,可以使用运行时匹配:
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"
}
但是,这种做法是非常非常糟糕的。它是不可扩展的。
您也可以使用类型 类 而不是隐式转换。
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
的子集上定义,并且不会应用隐式转换。
转换应该显式或事先完成。针对您的情况执行此操作的一种方法是采用可变参数或序列的方法:
def resolveThem (resolvers: Option[Resolver]*): Iterable[String] = {
resolvers.flatten.map(_.resolve)
}
resolveThem(Option(new A), Option(new B))
我有一个实例序列,其中每个实例都可以隐式转换为同一类型。 转换这种序列的最佳方法是什么?
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
}
- 您只能在编译器可以使用精确类型时使用隐式。一旦将对象放入简单的
List
中,它们各自的类型就会消失。 (不过你可以使用HList
。) - 对于两个参数,您只需使用您的工作方法即可。
要获得更多参数,您可能需要一个只有一个参数的构建器。
trait Builder { def add[A: Resolver](a: A): Builder = { use(a.resolve) this } }
如果只有几个类,可以使用运行时匹配:
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" }
但是,这种做法是非常非常糟糕的。它是不可扩展的。
您也可以使用类型 类 而不是隐式转换。
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
的子集上定义,并且不会应用隐式转换。
转换应该显式或事先完成。针对您的情况执行此操作的一种方法是采用可变参数或序列的方法:
def resolveThem (resolvers: Option[Resolver]*): Iterable[String] = {
resolvers.flatten.map(_.resolve)
}
resolveThem(Option(new A), Option(new B))