Tipos de Datos Estructurados

🧱 Tipos de Datos Estructurados

Los tipos de datos estructurados son construcciones que te permiten organizar y agrupar datos relacionados bajo una misma entidad. Son fundamentales para modelar conceptos complejos en tus contratos inteligentes.

  • Structs: Estructuras que agrupan campos con nombre y tipos diferentes.

  • Enums: Tipos que pueden contener uno de varios valores posibles predefinidos.

  • Tuplas: Colecciones ordenadas y de tamaño fijo que pueden contener elementos de diferentes tipos.

  • Arrays: Colecciones de elementos del mismo tipo con longitud fija.

1. Structs 🏗️

Las structs en Rust te permiten agrupar campos con nombres y tipos diferentes. Es como crear tu propio "molde" para agrupar datos relacionados.

rustCopiarEditarstruct Persona {
    nombre: String,
    edad: u32,
}

fn main() {
    let persona = Persona {
        nombre: String::from("Juan"),
        edad: 30,
    };
    println!("{} tiene {} años 👤", persona.nombre, persona.edad);
}

2. Enums 🎨

Los enums definen un tipo que puede ser uno de varios valores predefinidos. Son muy útiles para representar estados o variantes.

rustCopiarEditarenum Estado {
    Activo,
    Inactivo,
    Desconocido,
}

fn main() {
    let estado = Estado::Activo;
    match estado {
        Estado::Activo => println!("¡Está activo! 😊"),
        Estado::Inactivo => println!("Está inactivo. 😴"),
        Estado::Desconocido => println!("Estado desconocido. 🤔"),
    }
}

3. Tuplas 🔗

Las tuplas son colecciones ordenadas de tamaño fijo que pueden contener elementos de diferentes tipos. ¡Son perfectas para agrupar datos relacionados sin necesidad de nombres!

rustCopiarEditarfn main() {
    let persona: (&str, u32) = ("Ana", 25);
    println!("{} tiene {} años 👩", persona.0, persona.1);
}

4. Arrays 📚

Los arrays son colecciones de elementos del mismo tipo con una longitud fija. Se usan cuando conoces la cantidad exacta de elementos y estos son del mismo tipo.

rustCopiarEditarfn main() {
    let numeros: [i32; 5] = [1, 2, 3, 4, 5];
    println!("El primer número es: {} ", numeros[0]);
}

Contratos inteligentes ejemplo:

En esta ocasión vamos a crear un contrato independiente por cada tipo de dato de la siguiente manera.

Abrimos la consola en la ruta donde deseamos crear el proyecto y ejecutamos.

stellar contract init structured_data_types --name structured_data_types

Borramos todo el código y ponemos lo siguiente:

#![no_std]
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, String, };

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TaskStatus {
    Open = 0,
    InProgress = 1,
    Completed = 2,
}

#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Task {
    pub id: u32,
    pub description: String,
    pub status: TaskStatus,
    pub assignee: Address,
}

#[contract]
pub struct SimpleContract;
#[contractimpl]
impl SimpleContract {
    // Función que busca una fruta en un array y devuelve su posición o -1 si no la encuentra.
    pub fn find_fruit(env: Env,fruit: String) -> i32 {
        let fruits: [String; 5] = [
            String::from_str(&env,"manzana"),
            String::from_str(&env,"banana"),
            String::from_str(&env,"naranja"),
            String::from_str(&env,"uva"),
            String::from_str(&env,"fresa"),
        ];

        for (index, f) in fruits.iter().enumerate() {
            if f == &fruit {
                // Compara la fruta dada con cada elemento del array.
                return index as i32; // Devuelve la posición (índice) si la encuentra.
            }
        }

        -1 // Devuelve -1 si la fruta no está en el array.
    }

 
    // Función que crea una tarea y devuelve el struct
   pub fn create_task(env: Env, id: u32, description: String, assignee: Address) -> Task {
        Task {
            id,
            description,
            status: TaskStatus::Open,
            assignee,
        }
    }
 
     // Función que devuelve una tupla con información
    pub fn get_info(env: Env) -> (String, i32) {
        (String::from_str(&env,"Ejemplo Simple"), 123)
    }

    // Función que devuelve la descripción del estado de la tarea
    pub fn get_status_description(env: Env,status: TaskStatus) -> String {
        match status {
            TaskStatus::Open => String::from_str(&env,"Abierta"),
            TaskStatus::InProgress => String::from_str(&env,"En Progreso"),
            TaskStatus::Completed => String::from_str(&env,"Completada"),
        }
    }
}

Explicación del contrato

📌 Estructuras y Tipos del Contrato

1. Atributo #![no_std]

  • Indica que el contrato no utiliza la biblioteca estándar de Rust, lo que es común en entornos embebidos o en contratos inteligentes para reducir dependencias y adaptarse a restricciones de recursos.

2. Macros de Contrato

  • #[contract], #[contractimpl] y #[contracttype] Estas macros son proporcionadas por el soroban_sdk y se usan para marcar:

3. Enum TaskStatus

  • Define los posibles estados de una tarea:

    • Open (valor 0)

    • InProgress (valor 1)

    • Completed (valor 2)

  • Se deriva de Clone, Debug, Eq y PartialEq para facilitar la clonación, la depuración y la comparación de valores.

4. Struct Task

  • Representa una tarea y contiene:

    • id: u32: Identificador único de la tarea.

    • description: String: Descripción de la tarea.

    • status: TaskStatus: Estado actual de la tarea.

    • assignee: Address: Dirección del usuario asignado a la tarea.

  • Address es un tipo que representa direcciones de cuentas o contratos en Soroban. Más información en la documentación de Address.

5. Tipos del SDK


🛠 Funciones del Contrato

1. find_fruit

pub fn find_fruit(env: Env, fruit: String) -> i32 {
    let fruits: [String; 5] = [
        String::from_str(&env,"manzana"),
        String::from_str(&env,"banana"),
        String::from_str(&env,"naranja"),
        String::from_str(&env,"uva"),
        String::from_str(&env,"fresa"),
    ];

    for (index, f) in fruits.iter().enumerate() {
        if f == &fruit {
            // Si encuentra la fruta, retorna el índice convertido a i32.
            return index as i32;
        }
    }
    // Si no se encuentra, retorna -1.
    -1
}
  • Descripción: Busca en un arreglo de 5 frutas (como cadenas) la que coincida con la cadena de entrada fruit y devuelve su posición (índice).

  • Mecanismo:

    • Se crea un arreglo estático de frutas.

    • Se recorre el arreglo utilizando enumerate(), que proporciona el índice y el elemento.

    • Si se encuentra una coincidencia (usando if), se retorna el índice.

    • Si no hay coincidencia, se retorna -1.

2. create_task

pub fn create_task(env: Env, id: u32, description: String, assignee: Address) -> Task {
    Task {
        id,
        description,
        status: TaskStatus::Open,
        assignee,
    }
}
  • Descripción: Crea una nueva tarea con un identificador, descripción y usuario asignado. El estado inicial de la tarea se establece en TaskStatus::Open.

  • Mecanismo:

    • Se construye una instancia de la estructura Task con los valores proporcionados.

    • Se asigna el estado inicial de la tarea como abierta.

3. get_info

pub fn get_info(env: Env) -> (String, i32) {
    (String::from_str(&env,"Ejemplo Simple"), 123)
}
  • Descripción: Devuelve una tupla que contiene un mensaje y un número entero.

  • Mecanismo:

    • Se crea una cadena "Ejemplo Simple".

    • Se retorna junto a un entero fijo 123.

4. get_status_description

rustCopiarEditarpub fn get_status_description(env: Env, status: TaskStatus) -> String {
    match status {
        TaskStatus::Open => String::from_str(&env,"Abierta"),
        TaskStatus::InProgress => String::from_str(&env,"En Progreso"),
        TaskStatus::Completed => String::from_str(&env,"Completada"),
    }
}
  • Descripción: Devuelve una cadena descriptiva según el estado de una tarea.

  • Mecanismo:

    • Se utiliza la estructura de control match para evaluar el valor del TaskStatus.

    • Según el caso (Open, InProgress, Completed), se retorna la cadena correspondiente: "Abierta", "En Progreso" o "Completada".

  • Contexto Teórico del match: En Rust, match es similar a la instrucción switch de otros lenguajes, pero es más poderoso, permitiendo comparar contra patrones y asegurando que todos los casos sean tratados o manejados mediante un caso por defecto. Esto proporciona una forma segura y expresiva de controlar el flujo del programa.


📌 Resumen General

Este contrato inteligente demuestra:

  • Definición de Tipos Personalizados: Con el enum TaskStatus y la estructura Task, se modelan estados y tareas para un posible sistema de gestión.

  • Búsqueda en Arreglos: La función find_fruit muestra cómo recorrer un arreglo de cadenas y buscar un elemento.

  • Creación y Manejo de Estructuras: La función create_task crea una tarea inicializada con un estado predeterminado.

  • Uso de Tuplas y match: La función get_info devuelve información empaquetada en una tupla y get_status_description utiliza match para retornar descripciones basadas en el estado.

Compilación del contrato

Ejecutamos lo siguiente:

Stellar contract build

Despliegue del contrato

Para Mac y Linux el salto de línea es con el carácter " \" y en Windows con el carácter " ´ "

Reemplaze el simbolo * por el respectivo carácter de salto de linea a su sistema operativo.

stellar contract deploy *
  --wasm target/wasm32-unknown-unknown/release/structured_data_types.wasm *
  --source developer *
  --network <Identity> *
  --alias structured_data_types
Ejecución de prueba

Pruebas del contrato

Para Linux y Mac el salto de línea de la instrucción es con el carácter " \ " para Windows con el carácter " ` "

función find_fruit

stellar contract invoke `
--id <CONTRACT_ID> *
--source <Identity> `
--network testnet `
-- <Identity>`
find_fruit `
--fruit "manzana"
Ejecución de prueba

Función create_task

stellar contract invoke *
  --id <CONTRACT_ID> *
  --source<Identity> *
  --network testnet *
  -- *
  create_task *
--id 1 *
--description "Tarea de ejemplo" *
--assignee <Stellar address>"
Ejecución de ejemplo

Función get_info

stellar contract invoke `
  --id <CONTRACT_ID> *
  --source <identity> `
  --network testnet `
  -- `
  get_info
Ejecución de prueba

Función get_status_description

stellar contract invoke `
  --id <CONTRACT_ID> `
  --source <identity> `
  --network testnet `
  --  `
get_status_description  `
--status 0
Ejecución de prueba

Last updated

Was this helpful?