在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
}
但这真的没有吸引力,因为它基本上使得皮条客多余;一个人可能也明确地通过了双射,但当然你失去了使用双射的能力因范围而异。
这个问题有什么好的解决方案吗?
答案 0 :(得分:5)
这是怎么回事?
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: Either[Bijection[A, B], Bijection[B, A]]): B = f.fold(_ apply a, _ unapply a)
}
trait EitherLow {
implicit def left[A, B](implicit a: A): Either[A, B] = Left(a)
}
object Either extends EitherLow {
implicit def right[A, B](implicit b: B): Either[A, B] = Right(b)
}
import Bijection._
import Either._
1.as[String]
"1".as[Int]