2012-03-04 12 views
6
  • Tengo 3 clases Scala (A, B, C).
  • tengo una conversión implícita de la A -> B y uno de B -> C

En algún momento de mi código, quiero llamar a un método C sobre A. ¿Es esto posible? Una solución que surgió es tener una conversión de A -> C, pero eso parece algo redundante.Conversión implícita transitiva Scala

Nota:

  • Cuando llamo métodos B en un trabaja.
  • Cuando llamo a los métodos C en B, funciona.
  • Cuando llamo métodos C en A se dice que no se encontró el método en el cuerpo de un

Gracias ...

+6

Sugerencia: esto se parece más a _transitivity_ than _associativity_. Y no eres la primera persona en querer esto para las implicaciones de Scala. También 'A -> C' es probablemente un error tipográfico para' B -> C' en su segunda línea? –

+0

Gracias. Estaba en un apuro. –

+3

también eche un vistazo a: [cómo-puedo-i-cadena-implícita-en-scala] (http://stackoverflow.com/questions/5332801/how-can-i-chain-implicits-in-scala) –

Respuesta

6

Parece algo redundante, pero la conversión A -> C es exactamente lo que debe proporcionar. La razón es que si las implícitas son raras, las cadenas transitivas también son raras, y probablemente sean lo que quieres. Pero si las implicaciones son comunes, es probable que puedas convertir cualquier cosa en algo (o, si agregas un aspecto práctico implícito, de repente todo tipo de comportamientos cambiarán porque has abierto caminos diferentes para la conversión implícita).

Puede hacer que Scala encamine las conversiones implícitas por usted, sin embargo, si especifica que se debe hacer. La clave es usar genéricos con <% que significa "se puede convertir a". Aquí hay un ejemplo:

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 
+0

Gracias por la respuesta rápida. –

+0

Sí, probé el <% y funcionó. Pero también generó un extraño implícito de Array [String] => Unit compiler error. Así que he vuelto a cerrar la brecha manualmente. Tanques para tu ayuda. –

9

Parece que cometió un error tipográfico cuando escribió la pregunta . ¿Quiso decir que tiene conversiones implícitas de A -> B y B -> C, y que encuentra una conversión A -> C redundante?

Scala tiene una regla que sólo se aplicará una conversión implícita cuando sea necesario (pero nunca dos), por lo que no se puede simplemente esperar Scala para componer mágicamente A -> B y B -> C para hacer la conversión que necesita. Deberá proporcionar su propia conversión A -> C. No es redundante

+4

Una razón por la cual este es el caso es que puede haber múltiples posibilidades para el tipo medio. Si existen conversiones implícitas 'A -> B1',' B1 -> C' y 'A -> B2',' B2 -> C', el compilador no podrá adivinar cuál quiere. – hammar

+0

Gracias por la respuesta rápida. –

+0

con 'implicit def transitivo [A, B, C] (implícito a2b: A => B, b2c: B => C): A => C = (a: A) => b2c (a2b (a)) 'teóricamente es posible hacer una resolución transitiva. Pero en ese caso, cada 'implícitamente [A => B]' diverge, ya que hay implícito '$ concuerda [A]: A => A' - el algoritmo de resolución termina en bucle. – phadej

Cuestiones relacionadas