簡體   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