如何在没有歧义的情况下用不同的证据重载泛型方法? [英] How to overload generic method with different evidence without ambiguity?
本文介绍了如何在没有歧义的情况下用不同的证据重载泛型方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有一个自定义的 compare
方法,该方法带有两个参数.预计其中一个可以隐式转换为另一个:
I have a customized compare
methods that takes two parameters. One of them are expected to be implicitly convertible to another:
object Test extends App {
def compare[T1, T2](a: T1, b: T2)(implicit ev: T1 => T2) = compareImpl[T2](ev(a), b)
def compare[T1, T2](a: T1, b: T2)(implicit ev: T2 => T1) = compareImpl[T1](a, ev(b))
def compareImpl[T](a: T, b: T) = a == b
case class Foo(s: String)
case class Bar(s: String)
implicit def foo2bar(f: Foo): Bar = Bar(f.s)
println(compare(Foo("hello"), Bar("hello")))
}
但是此代码段给了我错误:
However this snippet gives me error:
error: ambiguous reference to overloaded definition,
both method compare in object Test of type [T1, T2](a: T1, b: T2)(implicit ev: T2 => T1)Boolean
and method compare in object Test of type [T1, T2](a: T1, b: T2)(implicit ev: T1 => T2)Boolean
match argument types (Test.Foo,Test.Bar) and expected result type Any
implicit def foo2bar(f: Foo): Bar = Bar(f.s)
如果我删除第二个 compare
,它可以工作,但是如果我执行 compare(Bar("hello),Foo(" hello))
,它将不会't编译.
If I remove the second compare
, it works, but then if I do compare(Bar("hello), Foo("hello"))
it won't compile.
我怎么能毫不含糊地拥有这两个版本?
How can I have these two versions without ambiguity?
推荐答案
不带宏的解决方案(基于类型类)
Solution without macros (it's based on type classes)
def compare[T1, T2](a: T1, b: T2)(implicit cmp: Compare[T1, T2]) = (compareImpl[cmp.T] _).tupled(cmp(a, b))
def compareImpl[T](a: T, b: T) = a == b
trait Compare[T1, T2] {
type T
type Out = (T, T)
def apply(a: T1, b: T2): Out
}
object Compare {
type Aux[T1, T2, T0] = Compare[T1, T2] { type T = T0 }
def instance[T1, T2, T0](f: (T1, T2) => (T0, T0)): Aux[T1, T2, T0] = new Compare[T1, T2] {
override type T = T0
override def apply(a: T1, b: T2): Out = f(a, b)
}
implicit def directCompare[T1, T2](implicit ev: T1 => T2): Aux[T1, T2, T2] = instance((a, b) => (ev(a), b))
implicit def reverseCompare[T1, T2](implicit ev: T2 => T1): Aux[T1, T2, T1] = instance((a, b) => (a, ev(b)))
}
case class Foo(s: String)
case class Bar(s: String)
implicit def foo2bar(f: Foo): Bar = Bar(f.s)
println(compare(Foo("hello"), Bar("hello"))) // true
或者,如果需要,您甚至可以优先选择正确的方向和相反的方向
Or you can even prioritize direct and reverse directions if you want
def compare[T1, T2](a: T1, b: T2)(implicit cmp: Compare[T1, T2]) = (compareImpl[cmp.T] _).tupled(cmp(a, b))
def compareImpl[T](a: T, b: T) = a == b
trait Compare[T1, T2] {
type T
type Out = (T, T)
def apply(a: T1, b: T2): Out
}
trait LowPriorityCompare {
type Aux[T1, T2, T0] = Compare[T1, T2] { type T = T0 }
def instance[T1, T2, T0](f: (T1, T2) => (T0, T0)): Aux[T1, T2, T0] = new Compare[T1, T2] {
override type T = T0
override def apply(a: T1, b: T2): Out = f(a, b)
}
implicit def reverseCompare[T1, T2](implicit ev: T2 => T1): Aux[T1, T2, T1] = instance((a, b) => (a, ev(b)))
}
object Compare extends LowPriorityCompare {
implicit def directCompare[T1, T2](implicit ev: T1 => T2): Aux[T1, T2, T2] = instance((a, b) => (ev(a), b))
}
case class Foo(s: String)
case class Bar(s: String)
implicit def foo2bar(f: Foo): Bar = Bar(f.s)
implicit def bar2foo(f: Bar): Foo = Foo(f.s)
println(compare(Foo("hello"), Bar("hello"))) // true
这篇关于如何在没有歧义的情况下用不同的证据重载泛型方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文