我有以下方法:
def foo[A](x: =>A) = ???
def foo[B](x: =>WrapperType[B]) = ???
这不能编译,这是有道理的,因为在第一种方法中,A也可以代表WrapperType[B]
。我可以在运行时检查x
的类型,但似乎应该有一种在编译时这样做的方法。我怎样才能克服这个问题?
注意:上面的代码是我的真实代码的简化,它是:
def ifEmpty[B](errors:Seq[Error]*)(right: =>B): Either[Seq[Error], B] =
if( areAllEmpty(errors) ) Right(right)
else Left(errors.flatten)
def ifEmpty[C](errors:Seq[Error]*)(right: =>Either[Seq[Error], C]): Either[Seq[Error], C] =
if( areAllEmpty(errors) ) right
else Left(errors.flatten)
答案 0 :(得分:5)
这是消除签名歧义的通常方法(黑客):
scala> :pa
// Entering paste mode (ctrl-D to finish)
object Y {
def f[A](a: => A) = 1
def f[A](a: => Either[Exception, A])(implicit d: DummyImplicit) = 2
}
// Exiting paste mode, now interpreting.
defined object Y
scala> Y.f(42)
res0: Int = 1
scala> Y.f(Right(42))
res1: Int = 2
你的foo
擦除了相同的签名,因为params变成了引擎盖下的功能。
但是,对于Scala,foo(Wrapper)
比foo(A)
更具体。
您的示例实际代码无法工作,因为它是双重定义:重载仅考虑第一个参数列表。
编辑:不要对其进行测试this way.
答案 1 :(得分:2)
有一种方法,但它涉及某种类型的hackery并可能将您的逻辑定位在远离方法调用的位置:
def foo[A](f: => A)(implicit switch: Switch[A]) = switch(f)
通过这个,您现在可以在变量f
的返回类型上切换逻辑。
trait Switch[A]{
def apply(f: => A): Whatever
}
object Switch extends LowPrioritySwitch{
def apply[A](implicit switch: Switch[A]) = switch
implicit def wrapped[B] = new Switch[WrappedArray[B]]{
def apply(f: => WrappedArray[B]) = ...
}
}
trait LowPrioritySwitch{
implicit def any[A] = new Switch[A]{
def apply(f: => A) = ...
}
}
所有这一切都是为了利用隐式解决方案。也就是说,在尝试匹配特征中找到的下一个隐式之前,编译器将尝试匹配对象定义中的第一个隐式。因此这个名字。
答案 2 :(得分:0)
最后,我能够解决它,从每个答案中借鉴一个想法:
def ifEmpty[A](errors:Seq[Error]*)(implicit magnet:IfEmptyMagnet[A]): Either[Seq[Error], A] = magnet(errors:_*)
trait IfEmptyMagnet[+A] {
def areAllEmpty(seqs: Seq[Any]*) = seqs.forall(_.size == 0)
def apply(errors:Seq[Error]*): Either[Seq[Error], A]
}
implicit def ifEmptyMagnet[A](a: => A) = new IfEmptyMagnet[A]{
def apply(errors:Seq[Error]*): Either[Seq[Error], A] = {
if( areAllEmpty(errors) ) Right(a)
else Left(errors.flatten)
}
}
implicit def ifEmptyMagnet[A](a: => Either[Seq[Error], A])(implicit d: DummyImplicit) = new IfEmptyMagnet[A]{
def apply(errors:Seq[Error]*): Either[Seq[Error], A] = {
if( areAllEmpty(errors) ) a
else Left(errors.flatten)
}
}