我正在定义一些Scala implicits,以便更轻松地使用特定的不可更改的Java类集。下面的Scala代码是一个简单的例子,显然看起来很疯狂,在现实世界中,我试图从Monkey,Tree&中隐含地获取特定资源(而不是数字时代)。鸭子用于各种方法,如purchaseCandles()
:
// actually 3 Java classes I can not change:
case class Monkey(bananas: Int)
case class Tree(rings: Int)
case class Duck(quacks: Seq[String])
// implicits I created to make my life easier...
implicit def monkey2Age(monkey: Monkey): Int = monkey.bananas / 1000
implicit def tree2Age(tree: Tree): Int = tree.rings
implicit def duck2Age(duck: Duck): Int = duck.quacks.size / 100000
// one of several helper methods that I would like to define only once,
// only useful if they can use an implicit parameter.
def purchaseCandles()(implicit age: Int) = {
println(s"I'm going to buy $age candles!")
}
// examples of usage
{
implicit val guest = Monkey(10000)
purchaseCandles()
}
{
implicit val guest = Tree(50)
purchaseCandles()
}
{
implicit val guest = Duck(Seq("quack", "quack", "quack"))
purchaseCandles()
}
编译器错误,发生3次:
could not find implicit value for parameter age: Int
purchaseCandles()
^
撇开此示例代码疯狂的许多不同方式,我真正的问题是:隐式值的隐式转换是否满足Scala中的隐式参数?
答案 0 :(得分:5)
简答:不。 Scala的编译器只会使用一个隐式的,所以如果它找不到implicit int
,它会停止并放弃。
但是,您可以编写purchaseCandles
方法来处理可以转换为Int
的类型,并且需要该类型的参数:
def purchaseCandles[A <% Int]()(implicit age : A) = {
val asAge : Int = age
println(s"I'm going to buy $asAge candles!")
}
强制应用隐式转换需要asAge
部分。
到目前为止,我似乎需要在这种情况下指定A
的类型,虽然我无法弄清楚原因:因为不应该存在可以隐式转换的类型的其他值到Int
(这也适用于全新的类型,所以它不是普遍存在的Int
。)但你可以这样做:
{
implicit val guest = Monkey(10000)
purchaseCandles[Monkey]()
}
然而,这种使用含义可能是一个坏主意!
答案 1 :(得分:1)
您实际上可以这样做:您只需要将隐式转换的参数标记为隐式:
implicit def monkey2Age(implicit monkey: Monkey): Int = monkey.bananas / 1000
implicit def tree2Age(implicit tree: Tree): Int = tree.rings
implicit def duck2Age(implicit duck: Duck): Int = duck.quacks.size / 100000
这将以他们想要的方式链接。
一如既往:小心,它也会在你不想要的地方这样做。顺便说一句,我强烈建议不要使用Int
类型的隐式参数(或其隐式值)。这太普通了。 (我有点假设这与你的例子中的情况一样)。