在 Scala 中,重载和隐式参数解析的相互作用似乎使以下代码无法使用。
trait Bijection[A, B] extends Function1[A, B] with Unapply[A, B] { self =>
def apply(a: A): B
def unapply(b: B): A
}
sealed trait Unapply[A, B] {
def unapply(b: B): A
}
object Bijection {
implicit def biject[A](a: A): Biject[A] = new Biject(a)
implicit object IntStringBijection extends Bijection[Int, String] {
override def apply(a: Int): String = a.toString
override def unapply(b: String): Int = b.toInt
}
}
sealed class Biject[A](a: A) {
def as[B](implicit f: Function1[A, B]): B = f(a)
def as[B](implicit f: Unapply[B, A]): B = f unapply a
}
这里的目标是让 a.as[B] 执行类型安全转换,而不管 Bijection[A,B] 或 Bijection[B,A] 在隐式范围内是否可用。
这不起作用的原因是隐式解析似乎发生在编译器中的重载消歧之后,并且由于 'as' 的两个实现具有相同的结果类型,编译器甚至没有尝试找出适当的隐式是否在可以执行转换的范围内。简而言之,在重载消歧中不使用隐式解析。
我想让'as'重载的原因是为了避免这个库的用户需要在调用站点对双射的“方向”进行编码;显然可以这样实现 Biject:
sealed class Biject[A](a: A) {
def viaForward[B](implicit f: Function1[A, B]): B = f(a)
def viaReverse[B](implicit f: Unapply[B, A]): B = f unapply a
}
但这真的很不吸引人,因为它本质上使皮条客变得多余;不妨明确地通过双射,但当然你失去了使所使用的双射根据范围而变化的能力。
这个问题有什么好的解决办法吗?