我有一组看起来像这样的类,它们(令人讨厌)不在单个继承层次结构中:
trait Mxy[A,B] { def apply(a: A): B }
trait Mzz[ C ] { def apply(c: C): C }
trait Mix[ B] { def apply(i: Int): B }
trait Mxi[A ] { def apply(a: A): Int }
trait Mii { def apply(i: Int): Int }
面临的挑战是使用转换器将Function1
映射到这些类中(因此您可以调用.m
来切换);直接隐式转换使得很难弄清楚代码实际上在做什么。
只要最具体的M
总是好的,那就可行了。您可以编写类似于
abstract class MxyMaker[A, B] { def m: Mxy[A, B] }
abstract class MiiMaker { def m: Mii }
trait Priority2 {
implicit def f2mxy[A, B](f: Function1[A, B]) =
new MxyMaker[A, B] { def m = new Mxy[A, B] { def apply(a: A) = f(a) } }
}
// Bunch of missing priorities here in the full case
object Convert extends Priority2 {
implicit def f2mii[A](f: Function1[A, Int])(implicit evA: Int =:= A) =
new MiiMaker { def m = new Mii{
def apply(i: Int) = (f.asInstanceOf[Function1[Int,Int]]).apply(i)
} }
}
现在每当你有一个Int => Int
时,你就得到一个Mii
,而对于其他任何东西,你得到一个Mxy
。 (如果您没有要求evA
,则((a: Any) => 5).m
会出现Mii
,因为其输入参数参数中的Function1会出现逆差。)
到目前为止一切顺利。但是,如果您所处的环境不需要Mii
而是Mxy
?
def muse[A, B](m: Mxy[A,B]) = ???
现在推断出最具体的类型不是你想要的。但是,唉,
scala> muse( ((i: Int) => 5).m )
<console>:18: error: type mismatch;
found : Mii
required: Mxy[?,?]
muse( ((i: Int) => 5).m )
^
现在怎样?如果Mxy
是Mii
的超类,那就没问题了,但事实并非如此,我无法改变它。我可以使用输出类型对m
进行参数化,并根据输出类型和进行一组类似类类型的事情,然后让用户手动输入.m[Mxy]
。但是我想跳过手动部分并以某种方式从调用muse
中获取类型上下文而不会弄乱像val mippy = ((i: Int) = 5).m
这样的内容。
精明的人可能会在野外想到这样的情况,但是更容易使用这种“最小化”来使原则正确。