【问题标题】:overloading methods based on implicits基于隐式的重载方法
【发布时间】:2017-05-06 14:07:21
【问题描述】:

我写了这段代码

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 dog,而在我的第二种情况下匹配有一个隐含的 val cat。所以它应该找到正确的隐式。

为什么不能正确解析?

我的环境是

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

【问题讨论】:

    标签: scala


    【解决方案1】:

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

    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")
    }
    

    【讨论】:

    • 是否有解决方法,或其他方式向编译器提供提示。并在上面得到我想要的。
    • 使用类型类
    • @KnowsNotMuch;不知道这次更新能否满足您的需求。
    • @KnowsNotMuch :) 与重载相比,隐式参数为您提供了更好(更强大)的临时多态性,因此将这两个功能结合起来看起来很奇怪。
    【解决方案2】:

    @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"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-30
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多