2010-05-18 24 views
7

Y más específicamente, ¿cómo funciona el BigInt para convertir int a BigInt?¿Puede alguien explicarme las conversiones implícitas en Scala?

En el código fuente se lee:

... 
implicit def int2bigInt(i: Int): BigInt = apply(i) 
... 

Cómo se invoca el código?

Puedo entender cómo funciona esta otra muestra: "Date literals".

En.

val christmas = 24 Dec 2010 

Definido por:

implicit def dateLiterals(date: Int) = new { 
    import java.util.Date 
    def Dec(year: Int) = new Date(year, 11, date) 
} 

Cuando int get pasarle el mensaje Dec con un int como parámetro, el sistema busca otro método que puede manejar la petición, en este caso Dec(year:Int)

Q1. ¿Tengo razón en mi comprensión de los literales de Date?

Q2. ¿Cómo se aplica a BigInt?

Gracias

+0

Creo que se refiere a las conversiones implícitas. Los parámetros implícitos son algo ligeramente diferente. – GClaramunt

+0

[Programación en Scala 1st Edition] (http://www.artima.com/pins1ed/): [Conversiones implícitas y parámetros] (http://www.artima.com/pins1ed/implicit-conversions-and-parameters). html) – user272735

Respuesta

11

Cuando un tipo de la proporcionada no coincide con el tipo esperado, el compilador Scala busca cualquier método en el ámbito marcado implícita de que toma el tipo proporcionado como parámetro y devuelve el tipo esperado como resultado. Si se encuentra, inserta la llamada al método en el medio. En el caso Bigint, supongamos que tiene un método

doSomethingWithBigInt(d:BigInt)=.... 

Y llamarlo con un entero:

doSomethingWithBigInt(10) 

A medida que los tipos no coinciden, el compilador generará Scala:

doSomethingWithBigInt(int2bigInt(10)) 

Suponiendo que el int2bigInt implícita está en el ámbito

+2

Para aclarar, utiliza un * implícito si hará que el código que no compilaría de otra manera lo haga *, no solo si hay un implícito que acepta el tipo encontrado como su argumento. –

+3

El alcance es una pista falsa. Scala buscará tales implicits en el objeto complementario de la clase original y en el objeto complementario de la clase de destino si se ha inferido esa clase de destino. En este caso, dado que la clase de destino es explícitamente BigInt, entonces se buscará implicitos en el acompañante de objetos de BigInt. –

+0

No quería entrar en detalles sobre el alcance :) – GClaramunt

7

el punto de s implícitos Tuff es rellenar cosas aburridas cuando claramente hay una sola forma correcta de hacerlo.

En el caso de los parámetros implícitos el compilador inserta un parámetro del contexto que debe ser lo que estaba pensando. Por ejemplo,

case class TaxRate(rate: BigDecimal) { } 
implicit var sales_tax = TaxRate(0.075) 
def withTax(price: BigDecimal)(implicit tax: TaxRate) = price*(tax.rate+1) 

scala> withTax(15.00) 
res0: scala.math.BigDecimal = 16.1250 

Como nos hemos marcado la tasa de impuestos como un parámetro implícito, y proporciona una variable implícita que puede ser llenado en cuando es necesario, no es necesario especificar el tipo de gravamen. El compilador rellena automáticamente withTax(15.00)(sales_tax)

En el caso de las conversiones implícitas , el compilador busca un método que puede tener un tipo que tiene y lo convierten en el tipo que se necesita. Esta conversión no puede encadenarse en circunstancias normales, por lo que debe obtener lo que necesita en un paso.

Existen dos casos en los que es probable que entren en juego conversiones implícitas. Uno está en el parámetro de una llamada a método: si el tipo es incorrecto, pero se puede convertir al tipo correcto (exactamente de una manera), el compilador convertirá para usted. El otro se encuentra en el presencia de una llamada a método - si el tipo realmente utilizado no tiene el método disponible, pero puede convertirlo a un tipo que sí lo tenga, se realizará la conversión y luego método será llamado.

Veamos un ejemplo de cada uno.

implicit def float2taxrate(f: Float) = TaxRate(BigDecimal(f)) 
scala> withTax(15.00)(0.15f) 
res1: scala.math.BigDecimal = 17.250000089406967200 

Aquí, llamamos a una tasa de impuesto explícito de 0.15f. Eso no coincide con el parámetro, que debe ser del tipo TaxRate, pero el compilador ve que podemos convertir los flotantes en tasas impositivas usando el implícito float2taxrate. Entonces lo hace por nosotros, llamando al withTax(15.00)(float2taxrate(0.15f))

Ahora el otro ejemplo.

class Currency(bd: BigDecimal) { 
    def rounded = bd.setScale(2,BigDecimal.RoundingMode.HALF_EVEN) 
} 
implicit def bigdec2currency(bd: BigDecimal) = new Currency(bd) 
scala> withTax(15.00)(0.15f).rounded 
res66: scala.math.BigDecimal = 17.25 

BigDecimal no tiene un método rounded, por lo withTax(15.00)(0.15f) no debería ser capaz de llamar a uno (ya que devuelve un BigDecimal). Pero hemos definido un Currency que tiene un método rounded y una conversión a Currency, por lo que la conversión implícita completa todos los detalles: bigdec2currency(withTax(15.00)(0.15f)).rounded.

En el caso de la conversión de Int a BigInt, el compilador lo usará cuando, por ejemplo, intente agregar 7 + BigInt(5). Esto no va a funcionar normalmente-- 7 es un Int y Int no sabe cómo agregarse a sí mismo a BigInt. Pero BigInt tiene un método + que puede agregarse a otro BigInt. Y el compilador ve que si pudiera convertir 7 a BigInt, podría usar ese método. La conversión implícita permite esa conversión, por lo que traduce 7 + BigInt(5) en int2bigInt(7)+BigInt(5).

(Nota: int2bigInt se define dentro de BigInt, por lo que para usarlo hay que import BigInt._ Y a su vez se remite al método apply(i: Int) del objeto BigInt, que es lo que le permite escribir BigInt(5) y tienen que trabajar (en lugar de. tener que pasar una cadena como con BigInteger en Java).)

+0

¡Gracias! Eso es más detallado que mi explicación. – GClaramunt

+0

Tuyo probablemente fue suficiente, pero decidí dejar una referencia/tutorial más extenso para aquellos que están menos familiarizados con Scala. –

Cuestiones relacionadas