Scala解析多个隐式参数

时间:2013-03-15 13:22:18

标签: scala implicits

在尝试回答this question时,我想出了以下代码:

    case class Monkey(bananas: Int) 
    case class Tree(rings: Int)
    case class Duck(quacks: Seq[String])

    implicit class IntLike(val x : Int) extends AnyVal

    implicit def monkey2Age(monkey: Monkey): IntLike = monkey.bananas / 1000
    implicit def tree2Age(tree: Tree): IntLike = tree.rings
    implicit def duck2Age(duck: Duck): IntLike = duck.quacks.size / 100000

    def purchaseCandles[A <% IntLike]()(implicit age : A) = {
      val asAge : IntLike = age
      println(s"I'm going to buy $asAge candles!")
    }              

    {
        implicit val guest = Tree(50)
        purchaseCandles()
    }

请注意,IntLike只是为了让我相信这不是一个专注于Int的问题。

这似乎是一个相当标准,如果不好,使用含义,我期待它愉快地工作。但是,在调用purchaseCandles()时,REPL会产生以下错误:

  

错误:含糊不清的隐含值:    两个值StringCanBuildFrom在对象Predef中的类型=&gt; scala.collection.generic.CanBuildFrom [字符串,字符,字符串]    树型的价值客人    匹配预期类型A

我不能为我的生活看到这是怎么回事。 A必然会有IntLike的视图范围,这是我刚刚发明的类型。 REPL确认没有可用的隐式视图:

  

阶&GT;隐含地[Tree =&gt; IntLike]

     

res14:Tree =&gt; IntLike = function1

但是

  

阶&GT;隐式[scala.collection.generic.CanBuildFrom [String,Char,String] =&gt; IntLike]

     

:18:错误:scala.collection.generic.CanBuildFrom没有隐式视图[String,Char,String] =&gt; IntLike。

那么StringCanBuildFrom如何成为合适的类型呢?编译器是否能够解决多个依赖的implicits,如果没有,为什么会显示错误?

2 个答案:

答案 0 :(得分:1)

在尝试回答之前,首先是减少的案例。请注意,您在调用purchaseCandles时没有提示A类型,我认为这是问题的根源。

object Foo

def test[A <% Foo.type](implicit bar: A) {}

test

错误:

<console>:10: error: ambiguous implicit values:
 both value StringCanBuildFrom in object Predef of type =>
     scala.collection.generic.CanBuildFrom[String,Char,String]
 and method conforms in object Predef of type [A]=> <:<[A,A]
 match expected type A
              test
              ^

StringCanBuildFrom似乎更像是一个令人困惑的错误消息。如果您专注于此处的conforms,则无法解决此问题的原因可能会更加明确:Predef.conform说明无论何时您要求隐式转换A => A,都可以通过以下方式保证:身份。这样,如果您有def foo[B <% A](b: B),则始终可以使用foo类型的值调用A,而无需定义任何类型的A => A


您要求解析未指定类型的隐式参数以及从未指定类型IntLike的转换。我认为这超出了隐式分辨率算法的范围。仍然是错误信息有点奇怪。

答案 1 :(得分:0)

仍然没有解释为什么它会失败 - 尽管如上所述,我认为由于未定义的输入类型,这对于隐式解析来说太多了,但你可以让它像这样工作:

    implicit def findIntLike[A <% IntLike](x: A): IntLike = x
    def purchaseCandles()(implicit age: IntLike) = {
      println(s"I'm going to buy $age candles!")
    }              

    implicit val guest = Tree(50)
    purchaseCandles()