Скала транзитивное неявное преобразование - PullRequest
6 голосов
/ 04 марта 2012
  • У меня есть 3 класса Scala (A, B, C).
  • У меня есть одно неявное преобразование из A -> B и одно из B -> C.

В какой-то момент моего кода я хочу вызвать метод C на A. Возможно ли это? Одно исправление, которое я придумал, - это преобразование из A -> C, но это выглядит несколько избыточным.

Примечание:

* * 1010 Когда я вызываю методы B для A, это работает. Когда я вызываю методы C на B, это работает. Когда я вызываю методы C для A, он говорит, что не нашел метод в теле A

Спасибо ...

Ответы [ 2 ]

9 голосов
/ 04 марта 2012

Кажется, вы сделали опечатку, когда написали вопрос.Вы хотели сказать, что у вас есть неявные преобразования из A -> B и B -> C, и что вы нашли A -> C преобразование избыточным?

В Scala есть правило, что оно будет применяться только один неявное преобразование при необходимости (но не два), поэтому вы не можете просто ожидать, что Scala волшебным образом создаст A -> B и B -> C, чтобы выполнить преобразование, которое вам нужно.Вам нужно будет предоставить собственное преобразование A -> C.Это не избыточно.

6 голосов
/ 04 марта 2012

Это кажется несколько избыточным, но преобразование A -> C - это именно то, что вы должны предоставить.Причина в том, что если последствия редки, транзитивные цепочки также редки, и, вероятно, то, что вы хотите.Но если последствия распространены, есть вероятность, что вы сможете превратить что-либо во что-либо (или, если вы добавите неявный на вид удобный, вдруг все виды поведения изменится, потому что вы открыли разные пути для неявного преобразования).

Однако вы можете включить в Scala цепочку неявных преобразований, если вы укажете, что это должно быть сделано.Ключ в том, чтобы использовать дженерики с <%, что означает «можно преобразовать в».Вот пример:

class Foo(i: Int) { def foo = i }
class Bar(s: String) { def bar = s }
class Okay(b: Boolean) { def okay = b }
implicit def to_bar_through_foo[T <% Foo](t: T) = new Bar((t: Foo).foo.toString)
implicit def to_okay_through_bar[U <% Bar](u: U) = new Okay((u: Bar).bar.length < 4)

scala> (new Foo(5)).okay
res0: Boolean = true
...