Capítulo 3 Día 2 - Recursos en Diccionarios y Arrays
Holaaaaa gente. Hoy, vamos a tomar nuestro entendimiento de los Recursos y aplicándola a arrays y diccionarios, algo que cubrimos en Capitúlo 2. En su propia manera ellos puede ser un poco fácil para manejar, pero los pones juntos y se complica un poco.
Video
Puedes ver este video desde 08:00 - El Fin (cubrimos el principio en la ultima dia): https://www.youtube.com/watch?v=SGa2mnDFafc
¿Por qué Diccionarios & Arrays?
Primero, ¿por qué estamos hablando sobre recursos en diccionarios, pero no recursos en structs? Pues, es importante notar al principio que no puedes almacenar recursos dentro de un struct. Aunque un struct es un contenedor de data, no podemos poner recursos adentro el.
Bueno. Entonces donde podemos almacenar un recurso?
- Adentro un diccionario o array
- Adentro un otro recurso
- Como un variable de estado de contrato
- Adentro un almacenamiento de una cuenta (hablamos sobre este más tarde)
Eso es todo. Hoy, hablamos sobre 1.
Recursos en Arrays
Es siempre mejor para aprender con los ejemplos, entonces abramos un Flow playground y desplegar el contrato nos usado en Capítulo 3 Día 1:
pub contract Test {
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
}
Hasta ahora solo tenemos 1 recurso con el tipo de @Greeting
. ¡Genial! Ahora intentemos a tener un variable de estado que almacena un listado de Greetings
en un array.
pub contract Test {
pub var arrayOfGreetings: @[Greeting]
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
init() {
self.arrayOfGreetings <- []
}
}
Darse cuenta que el tipo de arrayOfGreetings
: @[Greeting]
. Aprendimos ayer que los recursos siempre tiene el símbolo de @
frente a él. Esto también se aplica a los tipos de arrays que tienen recursos dentro de ellos, debes decírselo a Cadence que es un array de recursos poniendo el @
a frente de él. Debe asegurarse de que él @
esté fuera de los soportes, no dentro.
[@Greeting]
- esto es incorrecto
@[Greeting]
- esto es correcto
También darse cuenta que a dentro de la función de init
, lo inicializamos con el operador <-
, no =
. Una vez más, cuando manejamos los recursos (si ellos están dentro de los arrays, diccionarios, o por su cuenta), tenemos que usar <-
.
Añadido a un Array
¡Genial! Hicimos nuestro propio array de los recursos. Miremos cómo añadir un recurso a un array.
NOTA: Hoy, vamos a pasar recursos como argumentos a nuestras funciones. Esto significa que no vamos a preocuparnos sobre cómo se crearon los recursos, solo estamos usando funciones de ejemplos para mostrar como añadir a los arrays y diccionarios.
pub contract Test {
pub var arrayOfGreetings: @[Greeting]
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
pub fun addGreeting(greeting: @Greeting) {
self.arrayOfGreetings.append(<- greeting)
}
init() {
self.arrayOfGreetings <- []
}
}
En este ejemplo, sumamos una nueva función addGreeting
que toman el tipo de @Greeting
y añadirlo a el array usando la función de append
. ¿Parece fácil cierto? Este es exactamente como se parece para agregar a un array normalmente, sólo usamos el operador <-
para “mover” el recurso en el array.
Quitando de un Array
Bueno, hemos añadido a el array. Ahora cómo quitamos un recurso de él?
pub contract Test {
pub var arrayOfGreetings: @[Greeting]
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
pub fun addGreeting(greeting: @Greeting) {
self.arrayOfGreetings.append(<- greeting)
}
pub fun removeGreeting(index: Int): @Greeting {
return <- self.arrayOfGreetings.remove(at: index)
}
init() {
self.arrayOfGreetings <- []
}
}
Una vez más, es bastante sencillo. En un array normal, usaría la función de remove
para quitar un elemento. Es lo mismo para recursos, la única diferencia es usas el <-
para “mover” el recurso afuera de el array. ¡Genial!
Recursos en Diccionarios
Recursos en diccionarios son un poco más complicados. Una de las razones de esto es porque, si recuerdas de Capitúlo 2 Día 3, diccionarios siempre devuelve opcionales cuando al acceder los valores dentro de él. Esto hace que almacenar y recuperar recursos sea mucho más difícil. De cualquier manera, diría que los recursos más comúnmente se almacenan en diccionarios , por lo que es importante aprender cómo se hace.
Usemos un contrato similar para este ejemplo:
pub contract Test {
pub var dictionaryOfGreetings: @{String: Greeting}
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
init() {
self.dictionaryOfGreetings <- {}
}
}
Vamos a tener un diccionario que asigna una message
a el recurso de @Greeting
que contiene ese mensaje. Darse cuenta que el tipo del diccionario: @{String: Greeting}
. El @
está afuera de las llaves.
Añadido a un Diccionario
Hay 2 maneras diferentes para añadir un recurso a un diccionario. Miremos a los dos:
#1. Lo más fácil, pero estricto
La manera más fácil para añadir un a recurso a un diccionario es usando el operador de movimiento forzado <-!
, como así:
pub contract Test {
pub var dictionaryOfGreetings: @{String: Greeting}
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
pub fun addGreeting(greeting: @Greeting) {
let key = greeting.message
self.dictionaryOfGreetings[key] <-! greeting
}
init() {
self.dictionaryOfGreetings <- {}
}
}
En la función de addGreeting
, primero nos conseguiremos la key
accediendo el mensaje dentro de nuestro greeting
. Entonces añadimos a el diccionario por “movimiento forzado” greeting
en el diccionario de dictionaryOfGreetings
a una key
específica.
El operador de movimiento forzado <-!
significa básicamente: “Si ya hay un valor en destino, pánico y abortar el programa. De lo contrario, póngalo allí”
#2 - Complicada, pero manejar duplicados
La segunda manera para mover un recurso en un diccionario es usando la sintaxis de doble movimiento, como así:
pub contract Test {
pub var dictionaryOfGreetings: @{String: Greeting}
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
pub fun addGreeting(greeting: @Greeting) {
let key = greeting.message
let oldGreeting <- self.dictionaryOfGreetings[key] <- greeting
destroy oldGreeting
}
init() {
self.dictionaryOfGreetings <- {}
}
}
En este ejemplo, puedes ver algo extraño con el operador de doble movimiento que sucede. ¿Qué significa? Vamos a dividirlo en pasos:
- Toma cualquier valor que esté en la
key
específica y moverlo aoldGreeting
- Ahora que sabemos que no hay nada asignado a la
key
, movemosgreeting
a esa locación - Destruir
oldGreeting
En esencia, esta manera es más molesto y parece raro, pero te permite manejar el caso donde ya hay un valor allí. En el caso de arriba, nos destruir el recurso, pero si querías puedes hacer cualquier otra cosa.
Quitando de un Diccionario
Aquí es cómo eliminaría un recurso de un diccionario:
pub contract Test {
pub var dictionaryOfGreetings: @{String: Greeting}
pub resource Greeting {
pub let message: String
init() {
self.message = "Hello, Mars!"
}
}
pub fun addGreeting(greeting: @Greeting) {
let key = greeting.message
let oldGreeting <- self.dictionaryOfGreetings[key] <- greeting
destroy oldGreeting
}
pub fun removeGreeting(key: String): @Greeting {
let greeting <- self.dictionaryOfGreetings.remove(key: key) ?? panic("Could not find the greeting!")
return <- greeting
}
init() {
self.dictionaryOfGreetings <- {}
}
}
Recuerda en la sección de ‘Quitando de un Array’ todo lo que teníamos que hacer fue llamar la función de remove
. En diccionarios, accediendo un elemento devuelve un opcional, entonces tenemos que “desenvolver” el, de alguna manera. Si acabáramos de escribir esto..
pub fun removeGreeting(key: String): @Greeting {
let greeting <- self.dictionaryOfGreetings.remove(key: key)
return <- greeting
}
obtendríamos un error: “Tipos no coincidentes. Test.Greeting
esperado, consiguió Test.Greeting?
” Para resolverlo podemos utilizar pánico, o el operador de desenvolver a la fuerza !
, como así:
pub fun removeGreeting(key: String): @Greeting {
let greeting <- self.dictionaryOfGreetings.remove(key: key) ?? panic("Could not find the greeting!")
// OR...
// let greeting <- self.dictionaryOfGreetings.remove(key: key)!
return <- greeting
}
En Conclusión
¡Eso es todo para hoy! :D Ahora, te estarás preguntando: “Que si quiero acceder un elemento de un array/diccionario que tiene un recurso, y hacer algo con él?” Puedes hacer eso, pero tienes que primero mover el recurso afuera del array/diccionario, hacer algo, y muévelo hacia atrás. Mañana vamos a hablar sobre referencias, las cuales le permitirán hacer cosas con recursos sin tener que moverlos a todas partes. ¡Chao!
Búsquedas
Para la búsqueda de hoy, vas a tener 1 busqueda grande en vez de algunas búsquedas pequeñas.
- Escribir tu propio smart contract que contiene dos variables de estado: un array de recursos, y un diccionario de recursos. Añadir funciones para quitar y añadir a cada uno de ellos. Ellos tienen que ser diferentes de los ejemplos arriba.