基于implicits的重载方法

时间:2017-05-06 00:28:32

标签: scala

我写了这段代码

trait Pet
case class Dog() extends Pet
case class Cat() extends Pet
def foo(i: Int)(implicit d: Dog) = println("dog")
def foo(i: Int)(implicit c: Cat) = println("cat")
def doFoo(a: Pet) = {
  a match {
    case a: Dog => implicit val dog : Dog = a; foo(10)
    case a: Cat => implicit val cat : Cat = a; foo(10)
    case _ => println("unknown")
  }
}

我收到错误

cmd0.sc:8: ambiguous reference to overloaded definition,
both method foo in object cmd0 of type (i: Int)(implicit c: $sess.cmd0.Cat)Unit
and  method foo in object cmd0 of type (i: Int)(implicit d: $sess.cmd0.Dog)Unit
match argument types (Int)
    case a: Dog => implicit val dog : Dog = a; foo(10)
                                               ^
cmd0.sc:9: ambiguous reference to overloaded definition,
both method foo in object cmd0 of type (i: Int)(implicit c: $sess.cmd0.Cat)Unit
and  method foo in object cmd0 of type (i: Int)(implicit d: $sess.cmd0.Dog)Unit
match argument types (Int)
    case a: Cat => implicit val cat : Cat = a; foo(10)

但为什么感觉有歧义...因为在我的第一个案例匹配中有一个隐含的val狗,在我的第二个案例匹配中有一个隐含的val cat。所以它应该找到正确的含义。

为什么它没有正确解决?

我的环境是

Welcome to the Ammonite Repl 0.8.2
(Scala 2.12.1 Java 1.8.0_121)
                                           ^

2 个答案:

答案 0 :(得分:4)

编译器仅使用第一个参数组来消除重载方法的歧义。

def foo(x:Int)(y:Long): Long = y
def foo(x:Int)(y:Short): Short = y
foo(9)(2L)  // Error: ambiguous reference to overloaded definition

- 更新 -

您已经简化了代码示例,以至于很难说出您实际想要实现的目标。这会得到你之后的目标吗?

trait Pet {def foo(i: Int): Unit}
case class Dog() extends Pet {def foo(i: Int): Unit = println("dog")}
case class Cat() extends Pet {def foo(i: Int): Unit = println("cat")}

def doFoo(a: Pet) = a match {
  case d: Dog => d.foo(10)
  case c: Cat => c.foo(10)
  case _ => println("unknown")
}

答案 1 :(得分:0)

@jwvh回答是正确答案。

按照Seth Tisue的建议,这里是使用类型类实现这个问题(假设我的要求是正确的):

trait Pet[A] {
  def name: String
}

object Pet {
   def create[A](n: String) = new Pet[A] { def name = n }
}


case class Dog()
object Dog {
   implicit val dogIsPet = Pet.create[Dog]("dog")
}

case class Cat()
object Cat {
    implicit val catIsPet = Pet.create[Cat]("cat")
}

def foo[A](i: A)(implicit p: Pet[A]) = p.name

然后你可以像这样使用foo:

@ foo(Dog())
res5: String = "dog"
@ foo(Cat())
res6: String = "cat"