2010-12-31 28 views
14

escriboConversión implícita, ¿importación requerida o no?

object MyString { 
    implicit def stringToMyString(s: String) = new MyString(s)  
} 

class MyString(str: String) { 
    def camelize = str.split("_").map(_.capitalize).mkString 

    override def toString = str 
} 


object Parse { 
    def main(args: Array[String]) { 
    val x = "active_record".camelize 
    // ... 
    } 
} 

en mi programa. Esto causa un error de compilación. Después de insertar

import MyString.stringToMyString 

Entonces funciona.

De Odersky Programación en Scala Obtuve esa conversión implícita en el objeto complementario de la fuente o los tipos de destino esperados no necesitan ser importados.

Respuesta

16

conversión implícita en el objeto acompañante de la fuente o espera tipos de destino no necesitan ser importado.

Lo suficientemente cierto. Ahora, el método camelize se define en la clase MyString, y, de hecho, hay una conversión implícita a MyString dentro de su compañero de objeto. Sin embargo, no hay nada en el código que indique al compilador que MyString es el tipo de destino esperado .

Si, en cambio, que escribió esto:

val x = ("active_record": MyString).camelize 

entonces que iba a funcionar, porque el compilador sabría que espera"active_record" para ser un MyString, haciendo que se vea la conversión implícita dentro objeto MyString.

Esto puede parecer un poco restrictivo, pero en realidad funciona en varios lugares.Digamos, por ejemplo, que tenía:

class Fraction(num: Int, denom: Int) { 
    ... 
    def +(b: Fraction) = ... 
    ... 
} 

Y entonces tenía un código como este:

val x: Fraction = ... 
val y = x + 5 

Ahora, x tiene un método +, cuya esperada tipo es Fraction. Entonces, el compilador buscaría aquí una conversión implícita de Int a Fraction dentro del objeto Fraction (y dentro del objeto Int, si había uno, ya que ese es el tipo de fuente).

13

En esta situación necesita la importación porque el compilador no sabe de dónde sacó el método camelize. Si el tipo es clara, se compilará sin importar:

object Parse { 
    def foo(s: MyString) = s.camelize 

    def main(args: Array[String]) { 
    val x = foo("active_record") 
    println(x.toString) 
    } 
} 

Ver Pimp my library pattern, basado en Martin's article:

en cuenta que no es posible poner defs en el nivel superior, por lo que se puede' t define una conversión implícita con alcance global. La solución es colocar la definición dentro de un objeto, y luego importarlo, es decir,

object Implicits { 
    implicit def listExtensions[A](xs : List[A]) = new ListExtensions(xs) 
} 

Y a continuación, en la parte superior de cada archivo de origen, junto con sus otras importaciones:

import Implicits._ 
+1

IIRC puede poner la importación en el objeto del paquete, por lo que es al menos un poco "global" :-) – Landei

0

He probado el ejemplo de la clase Racional de programación en el libro Scala, poner un método implícito en su objeto acompañante:

object Rational { 
    implicit def intToRational(num: Int) = 
    new Rational(num) 
} 

pero el código

2 + new Rational(1, 2) 

no funciona. Para que se produzca la conversión, se aplica la regla del identificador único, es decir, debe importar el método explícito al ámbito aunque esté definido en el objeto complementario.

Cuestiones relacionadas