繁体   English   中英

Scala解析多个隐式参数

[英]Scala resolution of multiple implicit parameters

在试图回答这个问题时 ,我想出了以下代码:

    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的问题。

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

错误:模糊隐含值:两个值StringCanBuildFrom在对象Predef中的类型=> scala.collection.generic.CanBuildFrom [String,Char,String]和值类型为guest的类型匹配预期类型A

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

scala>隐式[Tree => IntLike]

res14:Tree => IntLike = function1

scala> implicitly [scala.collection.generic.CanBuildFrom [String,Char,String] => IntLike]

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

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

在尝试回答之前,首先是减少的案例。 请注意,您正在调用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) ,你总是可以用类型A的值调用foo ,而不需要定义任何类型的A => A


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

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

    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()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM