この質問に答えようとして、次のコードを思いつきました。
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 を呼び出すと、次のエラーが発生します。
エラー: あいまいな暗黙の値: 型 => scala.collection.generic.CanBuildFrom[String,Char,String] のオブジェクト Predef の値 StringCanBuildFrom と型 Tree の値 guest の両方が予想される型 A と一致します
私は一生、これがどのように当てはまるかを見ることができません。IntLike
A は、私が発明したばかりの型である のビュー バウンドを持つようにバインドされています。REPL は、使用可能な暗黙のビューがないことを確認します。
scala> 暗黙的に[Tree => IntLike]
res14: ツリー => IntLike = function1
しかし
scala> 暗黙的に[scala.collection.generic.CanBuildFrom[文字列、文字、文字列] => IntLike]
:18: エラー: scala.collection.generic.CanBuildFrom[String,Char,String] => IntLike から利用できる暗黙的なビューはありません。
では、どのようStringCanBuildFrom
に適切なタイプにすることができますか? コンパイラは複数の従属暗黙を解決できますか?そうでない場合、なぜこのエラーが表示されるのですか?