Может ли неявное преобразование неявного значения удовлетворить неявный параметр?
Я определяю некоторые последствия Scala, чтобы упростить работу с определенным неизменяемым набором классов Java. Следующий код Scala - это упрощенный пример, который явно выглядит сумасшедшим, в реальном мире я пытаюсь неявно получить определенные ресурсы (а не числовой возраст) от Monkey, Tree & Duck для использования в различных методах, таких как 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?
2 ответа
Краткий ответ: нет. Компилятор 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]()
}
Это использование имплицитов, однако, вероятно, плохая идея!
Вы действительно можете сделать это: вам просто нужно пометить параметры вашего неявного преобразования как неявные:
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
(или его неявное значение). Это просто слишком общий характер. (Я предполагаю, что это так же, как в вашем примере).