Scala 从函数到自定义类型集的转换
我有一组类似这样的类,它们(令人烦恼的)不在单一继承层次结构中:Scala 从函数到自定义类型集的转换,scala,implicit-conversion,typeclass,Scala,Implicit Conversion,Typeclass,我有一组类似这样的类,它们(令人烦恼的)不在单一继承层次结构中: 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 } 挑战在于使用转换器将Function
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
出现,因为函数1在其输入参数中的反差。)
到目前为止还不错。但如果您所处的环境不需要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 )
^
scala>muse((i:Int)=>5.m)
:18:错误:类型不匹配;
发现:信息产业部
必填项:Mxy[?,?]
缪斯(((i:Int)=>5.m)
^
现在怎么办?如果Mxy
是Mii
的一个超类,那就可以了,但它不是,我无法更改它。我可以用一个输出类型参数化m
,并拥有一组类似typeclass的东西,根据输出类型进行正确的转换,然后要求用户手动键入.m[Mxy]
。但是我想跳过手动部分,以某种方式从调用muse
中提取类型上下文,而不会弄乱val mippy=((I:Int)=5.m
之类的内容
机敏的人也许能在野外想到这样的情况,但使用这种“最小化”方法更容易获得正确的原则。缪斯需要一个MxyMaker如何?:
def muse[a,B](m:MxyMaker[a,B])={m.m}
或者如果您不想更改muse
则使用外部方法包装它:def museOuter[A,B](m:MxyMaker[A,B])={muse(m.m)}
@AkosKrivachy-不幸的是,我无法更改muse
,我关心的实际情况也不允许使用外部方法包装(因为像muse
)这样的方法太多了。既然不能让Mxy
成为超类Mii
,为什么不简单地定义从Mii
到Mxy[Int,Int]的隐式转换呢
?@RégisJean-Gilles-因为一般来说,你不希望他们在不知情的情况下到处乱跳,因为Mii是未装箱的,而Mxy是装箱的,使用Mii的唯一原因通常是为了性能。否则,我会这么做——总体来说,这是个好主意。