如何在没有歧义的情况下用不同的证据重载泛型方法? [英] How to overload generic method with different evidence without ambiguity?

查看:52
本文介绍了如何在没有歧义的情况下用不同的证据重载泛型方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆