¿Cómo funciona '20 segundos 'en Scala?

130

¿Cómo se compila lo siguiente:

import scala.concurrent.duration._

val time = 20 seconds

¿Qué está pasando realmente aquí?

ripper234
fuente

Respuestas:

171

Están sucediendo algunas cosas.

Primero, Scala permite que se omitan puntos y parens de muchas llamadas a métodos, por lo que 20 secondses equivalente a 20.seconds()*.

En segundo lugar, se aplica una "conversión implícita". Dado que 20es un método Inty Intno tiene ningún secondsmétodo, el compilador busca una conversión implícita que tome Inty devuelva algo que sí tiene un secondsmétodo, con la búsqueda limitada por el alcance de la llamada al método.

Ha importado DurationInt a su alcance. Como DurationIntes una clase implícita con un Intparámetro, su constructor define una Int => DurationIntconversión implícita . DurationInttiene un secondsmétodo, por lo que satisface todos los criterios de búsqueda. Por lo tanto, el compilador reescribe su llamada como new DurationInt(20).seconds**.

* Me refiero a esto libremente. 20.seconds()en realidad no es válido porque el secondsmétodo no tiene una lista de parámetros y, por lo tanto, los parens deben omitirse en la llamada al método.

** En realidad, esto no es del todo cierto porque DurationIntes una clase de valor, por lo que el compilador evitará ajustar el entero si es posible.

Aaron Novstrup
fuente
83
Cualquier tecnología suficientemente avanzada es indistinguible de la magia.
ripper234
44
Afortunadamente, la mayoría de los IDE son capaces de distinguirlo. Las conversiones implícitas se utilizan bastante en Scala. Si solo está leyendo el archivo de texto, puede ser confuso ("de dónde viene ese método"), pero con el soporte de herramientas adecuado debería poder orientarse, en ese momento Scala puede ser maravillosamente significativo y conciso. (por ejemplo, 20 segundos es mucho más legible que new DurationInt(20).seconds()siempre que sepas cómo lo hace)
William Billingsley
1
Si te encuentras usando implicidades, siempre pregúntate si hay una manera de lograr lo mismo sin su ayuda. twitter.github.com/effectivescala/#Types and Generics-Implicits
oluies
44
En realidad, el secondsmétodo se define sin parens, por lo que llamarlo con parens es un error.
Frank S. Thomas
1
@ Frank Eso es un buen punto. No quise sugerir que puedes escribir 20.seconds()en Scala, solo que el compilador está traduciendo la llamada de esa manera. Vale la pena señalar que Scala requiere que omita parens si el método correspondiente no tiene una lista de parámetros, como en este caso.
Aaron Novstrup
7

La "magia" que está sucediendo allí se llama "conversión implícita". Está importando las conversiones implícitas, y algunas de ellas manejan la conversión entre Int (y Double) a Duration. Eso es con lo que estás lidiando.

Bruno Reis
fuente
1
¿Alguna idea de por qué la importación se import scala.concurrent.duration._resuelve 20 secondspero en realidad la importación del DurationConversionsRasgo no? EDITAR : Acabo de darme cuenta de lo que realmente están importando DurationInt. Supongo que esto se debe a que no puedes importar el Rasgo real. ¿Solo una implementación concreta del rasgo?
franklin