Desempaquetado
El desempaquetado (unpacking) es una operación que permite extraer fácilmente objetos de listas y mapas. En Dogma, podemos usar expresiones de desempaquetado de listas y mapas, así como el operador de desempaquetado en línea.
Expresiones de desempaquetado
Por un lado, tenemos un tipo especial de expresión con la que se puede asignar elementos de una lista o mapa a varios contenedores de datos.
Expresión de desempaquetado de lista
Por un lado, tenemos el desempaquetado de una lista.
Consiste en asignar a una, dos o más variables los elementos consecutivos de una lista.
Cada variable recibe el elemento de la lista que le corresponda por su posición.
Así pues, la primera variable recibirá el elemento 0
; la segunda, el 1
; y así sucesivamente.
Si se indica más variables que elementos tiene la lista, a las que no reciban valor se les asignará nil
, a menos que indiquemos un valor explícitamente en la expresión de desempaquetado.
Su sintaxis es como sigue:
[variable, variable, variable...] = Exp
Cada variable tiene el siguiente formato:
Id
Id.Id
Id = Exp
Id.Id = Exp
Si el valor devuelto por la lista es nil
, se puede indicar el valor que debe asignarse en su lugar.
Para ello, se indica el valor predeterminado de la variable siguéndola de un =
y el valor en cuestión.
Existe una variable para recibir el resto de elementos de la lista. Su sintaxis es muy similar al del parámetro de resto:
...Id
...Id = Exp
Ejemplo:
[x, y, z, ...rest] = [1, 2, 3, 4, 5, 6]
#aquí tendremos:
# x = 1
# y = 2
# z = 3
# rest = [4, 5, 6]
Además del operador =
, podemos usar la expresión de desempaquetado con los operadores:
.=
, lo que creará campos privados y propiedades púbicas de sólo lectura para el acceso a los campos privados.:=
, lo que creará campos de sólo lectura, en cuyo caso, deben indicar los operadores.
o:
.?=
, el cual permite asignar a las variables del lado izquierdo el valor del lado derecho sólo si su valor actual es distinto denil
.
Veamos esto con un ejemplo ilustrativo:
[opts.host, opts.port, opts.db] ?= ["localhost", 6379, 0]
#similar a:
if opts.host == nil then opts.host = "localhost"
if opts.port == nil then opts.host = 6379
if opts.db == nil then opts.host = 0
Cuando se desea trabajar con varios campos de un mismo objeto, se puede utilizar la sintaxis variable{id,id,id...}
.
Así pues, las dos líneas siguientes hacen lo mismo:
[opts.host, opts.port, db] ?= ["localhost", 6379, 0]
[opts{host,port}, db] ?= ["localhost", 6379, 0]
Para indicar campos protegidos y/o privados, indicar :
o !
antes del nombre.
Ejemplo: opts{host,:port}
.
Expresión de desempaquetado de mapa
También es posible desempaquetar a partir de los miembros/campos de un mapa u objeto.
En este caso, las variables se delimitan entre llaves ({}
) en vez de entre corchetes ([]
):
{variable, variable, variable...} = Exp
Ejemplo:
{band, website} = {band = "The National", origin = "US", year = 1999, website = "americanmary.com"}
#aquí:
# band = "The National"
# website = "americanmary.com"
Con el desempaquetado de mapas, no se puede utilizar el operador ?=
, ni las variables de tipo a.b
, a:b
y ...resto
.
Definiciones de desempaquetado
Existen versiones de desempaquetado para las sentencias var
y const
.
Así, por ejemplo, para el desempaquetado de una lista tenemos:
var [variable, variable, variable...] = Exp
const [constante, constante, constante...] = Exp
Las variables declaradas pueden seguir las siguientes sintaxis:
nombre
. Variable a crear. Si no recibe ningún valor, se inicializará anil
.nombre = expresión
. Cuando se indica una expresión, si la variable no recibe un valor, se inicializará al valor indicado....nombre
. Cuando se indica este formato, la variable recibirá los restantes elementos de la lista, o sea, aquellos no asignados a ninguna de las variables anteriores._
, para aquellos casos en los que deseamos omitir el valor recibido.
He aqui un ejemplo ilustrativo:
var [x, _, y, ...z] = [1, 2, 3, 4, 5]
#aquí:
# x = 1
# el valor 2 se omite por el uso de _
# y = 3
# z = [4, 5]
También está disponible una versión para mapas u objetos:
var {variable, variable, variable...} = Exp
const {constante, constante, constante...} = Exp
Ejemplo:
var {name, website} = {
name = "Phoenix"
origin = "FR",
website = "wearephoenix.com"
}
#aquí:
# name = "Phoenix"
# website = "wearephoenix.com"
Operador de desempaquetado en línea
También se encuentra disponible el operador de desempaquetado en línea, representado por ...
, que tiene como objeto una lista en una llamada a función, simulando que escribimos cada uno de sus elementos uno detrás de otro.
Por ejemplo, supongamos la siguiente función de ejemplo:
fn sum(...args) -> res:num
for each arg in args do res += arg
Está claro que la función puede aceptar varios argumentos, tal como se muestra a continuación:
sum(1, 2, 3, 4) #devuelve 10
La idea del operador de desempaquetado en línea, ...
, es que si tenemos los argumentos a pasar en una lista podamos hacerlo como si estuviéramos escribiéndolos uno detrás de otro en la llamada. Así pues, lo siguiente:
l = [1, 2, 3, 4]
sum(...l) #devuelve 10
es lo mismo que escribir:
sum(1, 2, 3, 4)