¿Existe un equivalente en Scala del operador de desempaquetado de la lista de Python(también conocido como “*”)?
argument-passing (3)
En Python, tenemos el operador estrella (o "*" o "desempaquetar"), que nos permite desempaquetar una lista para un uso conveniente al pasar argumentos posicionales. Por ejemplo:
range(3, 6)
args = [3, 6]
# invokes range(3, 6)
range(*args)
En este ejemplo en particular, no guarda mucha escritura, ya que el range
solo toma dos argumentos. Pero puede imaginar que si hubiera más argumentos para el range
, o si los argumentos se leyeran desde una fuente de entrada, se devolvieran desde otra función, etc., esto podría ser útil.
En Scala, no he podido encontrar un equivalente. Considere los siguientes comandos ejecutados en una sesión interactiva de Scala:
case class ThreeValues(one: String, two: String, three: String)
//works fine
val x = ThreeValues("1","2","3")
val argList = List("one","two","three")
//also works
val y = ThreeValues(argList(0), argList(1), argList(2))
//doesn''t work, obviously
val z = ThreeValues(*argList)
¿Hay una forma más concisa de hacer esto además del método utilizado en val y
?
Hay algo similar para functiones: tupled
Convierte una función que toma n parámetros en una función que toma un argumento de tipo n-tuple.
Consulte esta pregunta para obtener más información: desempaquetar la tupla Scala
Un método de este tipo para matrices no tendría mucho sentido, ya que solo funcionaría con funciones con múltiples argumentos del mismo tipo.
No hay equivalente directo en scala. Lo más cercano que encontrará es el uso de _*
, que funciona solo con los métodos vararg. Por ejemplo, aquí hay un ejemplo de un método vararg:
def hello( names: String*) {
println( "Hello " + names.mkString(" and " ) )
}
que se puede utilizar con cualquier número de argumentos:
scala> hello()
Hello
scala> hello("elwood")
Hello elwood
scala> hello("elwood", "jake")
Hello elwood and jake
Ahora, si tiene una lista de cadenas y quiere pasarlas a este método, la manera de descomprimirlo es a través de _*
:
scala> val names = List("john", "paul", "george", "ringo")
names: List[String] = List(john, paul, george, ringo)
scala> hello( names: _* )
Hello john and paul and george and ringo
Puedes avanzar un poco hacia Python usando shapeless ,
Welcome to Scala version 2.11.0-20130208-073607-ce32c1af46 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import shapeless._
import shapeless._
scala> import Traversables._
import Traversables._
scala> case class ThreeValues(one: String, two: String, three: String)
defined class ThreeValues
scala> val argList = List("one","two","three")
argList: List[String] = List(one, two, three)
scala> argList.toHList[String :: String :: String :: HNil].map(_.tupled).map(ThreeValues.tupled)
res0: Option[ThreeValues] = Some(ThreeValues(one,two,three))
Como puede ver, se requiere un poco más de ceremonia en Scala con sin forma. Esto se debe a que la forma no impone restricciones de tiempo de compilación que se garantiza que se cumplen en el tiempo de ejecución (a diferencia de python, que fallará en el tiempo de ejecución si args
es del tamaño incorrecto o contiene elementos del tipo incorrecto) ... el tipo que espera que tenga la Lista (en este caso, exactamente tres Strings
) y esté preparado para manejar el caso en el que esa expectativa no se cumple (porque el resultado es explícitamente una Option
de ThreeValues
).