Translate

miércoles, 23 de agosto de 2023

Juego de Serie en Rust


Cuando quiero aprender un nuevo lenguaje desarrollo un juego de series, es decir aparece una serie con un valor faltante y el jugador debe completarlo.

Uno de los requerimientos no funcionales es que se pueda agregar una serie nueva fácilmente.

Vamos a desarrollar este juego en Rust:

Empecemos desarrollo de la serie, la serie tiene como responsabilidad generarse y si lo hacemos de esta manera podemos utilizar la potencia del polimorfismo, para que no quede acoplado la generación de la serie con el desarrollo del juego:

use rand::{thread_rng, Rng};


pub fn iniciar_secuencia() -> [u16;4] {

let semilla:u8 = thread_rng().gen_range(0..3);


match semilla {

    0 => return generar_secuencia_par(),

    1 => return generar_secuencia_inpar(),

        _ => return generar_fibonacci()

}

}

//Esta función genera la serie y para eso utiliza diferentes funciones que generan diferentes tipos de secuencias : 

fn generar_secuencia_par() -> [u16;4] {

let mut resultado:[u16;4] = [0; 4];

let semilla:u16 = thread_rng().gen_range(0..30);

for i in 0..4 {

resultado[i] = semilla * 2 + (i as u16) * 2;

}

resultado

}


fn generar_secuencia_inpar() -> [u16;4] {

let mut resultado:[u16;4] = [0; 4];

let semilla:u16 = thread_rng().gen_range(0..30);

for i in 0..4 {

resultado[i] = semilla * 2 + (i as u16) * 2 + 1;

}

resultado

}



fn generar_fibonacci() -> [u16;4] {

let mut _resultado:[u16;4] = [0; 4];

let semilla:u16 = thread_rng().gen_range(0..30);


for i in 0..4 {

if i < 2 {

_resultado[i] = semilla;

} else {

_resultado[i] = _resultado[i-1] + _resultado[i-2];

}

}

_resultado

}


Y listo!! ahora en el main tenemos que llamar a esta función y ver si esta bien el resultado: 


use std::io;


use crate::serie::iniciar_secuencia;


mod serie;


fn main() {

    let mut puntos = 0u8;

    loop {

        let serie:[u16;4] = iniciar_secuencia();


        println!("Serie: ");

        

        for i in 0..2 {

            print!(" {} ", serie[i]);

        }


        println!("_____ {} ", serie[3]);


        println!("Ingrese el valor faltante: ");

        let mut input = String::new();

        io::stdin().read_line(&mut input).expect("error: unable to read user input");

        let x = input.trim().parse().expect("Error!! debe ser un numero.");

        

        if serie[2].eq(&x) {

            println!("Ganaste !! ");

            puntos = puntos + 1;

        } else {

            println!("Perdiste !! ");

        }

        println!("Puntos :  {} ", puntos);

        println!("Desea continuar jugando? (y/n): ");

        let mut continuar = String::new();

        io::stdin().read_line(&mut continuar).expect("error: unable to read user input");

        

        if continuar.trim().ne("y"){

            return;

        }

    }    

}

Y eso es todo a jugar se a dicho!!

Dejo el repositorio git: https://github.com/emanuelpeg/secuenciaRust

lunes, 21 de agosto de 2023

Inscripciones Abiertas 2023 a cursos Gugler!!

 

PRENSA GUGLER  LAB 2023

  NOTICIAS ACTUALES

informacion  OFERTA ACADÉMICA


Estimado :

 Se encuentran abiertas las inscripciones para el segundo cuatrimestre del año 2023, para todas las capacitaciones dictadas por el Laboratorio de Investigación Gugler. Podés asegurar tu lugar en el curso y comisión que desees !!!.

Las clases inician:

  • Martes 12/09 , Miércoles 13/09, Jueves 14/09 o Sábado 16/09, según el curso que elegiste.

 

Inscribirteclic aquí

Cursos, Horarios y comisionesclic aquí.

 

 

Dictamos nuestros cursos en la Facultad de Ciencia y Tecnología, perteneciente a la Universidad Autónoma de Entre Ríos. En nuestro portafolio de capacitación encontrarás:

MODALIDAD PRESENCIAL

  • Cursos de Programación:
    Programación en PHP.
     
  • Cursos de Mantenimiento/Reparación:
    Reparación y Mantenimiento de PC.

 MODALIDAD DISTANCIA

  • Cursos de Programación:
    Programación Web Frontend.
    Programación en Java.
informacion   MÁS INFORMACIÓN 

informacion LABORATORIO DE INVESTIGACIÓN GUGLER

Si deseas comunicarte con nosotros, te recordamos que podes hacerlo a través de los siguientes portales, en los cuales encontrarás información sobre Gugler.

TEL: (0343) - 4975066 Interno 119

Sitio Oficial:  www.gugler.com.ar

Campus:  campusvirtual.gugler.com.ar

Sistema de Gestión Cursos:  sgc.gugler.com.ar

Sistema de Gestión Cursos Móvil: Aquí 

Sistema de Documentación:  sgd.gugler.com.ar

Sistema de Validación:  giua.gugler.com.ar

                   Twitter                Facebook

Laboratorio Gugler

partir del 2012, la Facultad de Ciencia y Tecnología nos declaro:  "Laboratorio de Investigación".

 

El laboratorio ha ampliado las incumbencias de Gugler, ya que además de la capacitación, la promoción y difusión del software libre, ahora abarcará actividades como publicaciones y proyectos de investigación, así como también el dictado y participación en conferencias o exposiciones de ámbitos académicos y científicos.

 

Ante cualquier duda comunicarse con nosotros a gugler_contacto@uader.edu.ar

GUGLER PRESS

Enums en Rust parte 3


Tamaños de enumeración:

use std::any::type_name;

use std::mem::{align_of, size_of};


fn dbg_size<T>() {

    println!("{}: size {} bytes, align: {} bytes",

        type_name::<T>(), size_of::<T>(), align_of::<T>());

}


enum Foo {

    A,

    B,

}


fn main() {

    dbg_size::<Foo>();

}


Internamente, Rust está utilizando un campo (discriminante) para realizar un seguimiento de la variante de enumeración.

Puede controlar el discriminante si es necesario (por ejemplo, para compatibilidad con C):

#[repr(u32)]
enum Bar {
    A,  // 0
    B = 10000,
    C,  // 10001
}

fn main() {
    println!("A: {}", Bar::A as u32);
    println!("B: {}", Bar::B as u32);
    println!("C: {}", Bar::C as u32);
}

Sin repr, el tipo discriminante ocupa 2 bytes, porque 10001 cabe en 2 bytes.

Pruebe otros tipos como

  • dbg_size!(bool): tamaño 1 byte, alineación: 1 byte,
  • dbg_size!(Opción<bool>): tamaño 1 bytes, alineación: 1 bytes (optimización de nicho, ver más abajo),
  • dbg_size!(&i32): tamaño 8 bytes, alineación: 8 bytes (en una máquina de 64 bits),
  • dbg_size!(Opción<&i32>): tamaño 8 bytes, alineación: 8 bytes (optimización de puntero nulo, ver más abajo).
Optimización de nicho: Rust fusionará patrones de bits no utilizados para el discriminante de enumeración.

Optimización de puntero nulo: para algunos tipos, Rust garantiza que size_of::<T>() es igual a size_of::<Option<T>>().

Código de ejemplo si desea mostrar cómo se vería la representación bit a bit en la práctica. Es importante tener en cuenta que el compilador no ofrece garantías con respecto a esta representación, por lo que es totalmente inseguro.

use std::mem::transmute;

macro_rules! dbg_bits {
    ($e:expr, $bit_type:ty) => {
        println!("- {}: {:#x}", stringify!($e), transmute::<_, $bit_type>($e));
    };
}

fn main() {
    // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise
    // representation of types.
    unsafe {
        println!("Bitwise representation of bool");
        dbg_bits!(false, u8);
        dbg_bits!(true, u8);

        println!("Bitwise representation of Option<bool>");
        dbg_bits!(None::<bool>, u8);
        dbg_bits!(Some(false), u8);
        dbg_bits!(Some(true), u8);

        println!("Bitwise representation of Option<Option<bool>>");
        dbg_bits!(Some(Some(false)), u8);
        dbg_bits!(Some(Some(true)), u8);
        dbg_bits!(Some(None::<bool>), u8);
        dbg_bits!(None::<Option<bool>>, u8);

        println!("Bitwise representation of Option<&i32>");
        dbg_bits!(None::<&i32>, usize);
        dbg_bits!(Some(&0i32), usize);
    }
}

Ejemplo más complejo si desea analizar qué sucede cuando encadenamos más de 256 opciones juntas.

#![recursion_limit = "1000"]

use std::mem::transmute;

macro_rules! dbg_bits {
    ($e:expr, $bit_type:ty) => {
        println!("- {}: {:#x}", stringify!($e), transmute::<_, $bit_type>($e));
    };
}

// Macro to wrap a value in 2^n Some() where n is the number of "@" signs.
// Increasing the recursion limit is required to evaluate this macro.
macro_rules! many_options {
    ($value:expr) => { Some($value) };
    ($value:expr, @) => {
        Some(Some($value))
    };
    ($value:expr, @ $($more:tt)+) => {
        many_options!(many_options!($value, $($more)+), $($more)+)
    };
}

fn main() {
    // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise
    // representation of types.
    unsafe {
        assert_eq!(many_options!(false), Some(false));
        assert_eq!(many_options!(false, @), Some(Some(false)));
        assert_eq!(many_options!(false, @@), Some(Some(Some(Some(false)))));

        println!("Bitwise representation of a chain of 128 Option's.");
        dbg_bits!(many_options!(false, @@@@@@@), u8);
        dbg_bits!(many_options!(true, @@@@@@@), u8);

        println!("Bitwise representation of a chain of 256 Option's.");
        dbg_bits!(many_options!(false, @@@@@@@@), u16);
        dbg_bits!(many_options!(true, @@@@@@@@), u16);

        println!("Bitwise representation of a chain of 257 Option's.");
        dbg_bits!(many_options!(Some(false), @@@@@@@@), u16);
        dbg_bits!(many_options!(Some(true), @@@@@@@@), u16);
        dbg_bits!(many_options!(None::<bool>, @@@@@@@@), u16);
    }
}

Enums en Rust parte 2


Ya vimos enums en Rust pero vamos a ver más característica: 


enum WebEvent {

    PageLoad,                 // Variant without payload

    KeyPress(char),           // Tuple struct variant

    Click { x: i64, y: i64 }, // Full struct variant

}


#[rustfmt::skip]

fn inspect(event: WebEvent) {

    match event {

        WebEvent::PageLoad       => println!("page loaded"),

        WebEvent::KeyPress(c)    => println!("pressed '{c}'"),

        WebEvent::Click { x, y } => println!("clicked at x={x}, y={y}"),

    }

}


fn main() {

    let load = WebEvent::PageLoad;

    let press = WebEvent::KeyPress('x');

    let click = WebEvent::Click { x: 20, y: 80 };


    inspect(load);

    inspect(press);

    inspect(click);

}


  • Solo se puede acceder a los valores en las variantes de enumeración después de hacer pattern matching. E
    • La expresión se compara con los patrones de arriba a abajo. 
    • Comenza desde arriba, buscando qué patrón coincide con el valor y luego ejecuta el código que se encuentra a la derecha de la flecha. 
  • Tenga en cuenta la ventaja que proporciona el compilador de Rust al confirmar cuándo se manejan todos los casos.
  • match inspecciona los campos publicos de  la enumeración.
  • Es posible recuperar el discriminante llamando a std::mem::discriminant(). Esto es útil, por ejemplo, si se implementa PartialEq para estructuras donde comparar valores de campo no afecta la igualdad.
  • WebEvent::Click { ... } no es exactamente lo mismo que WebEvent::Click(Click) con una estructura de nivel superior Click { ... }. La versión en línea no puede implementar rasgos, por ejemplo.

martes, 15 de agosto de 2023

Enums en Rust


La palabra clave enum permite la creación de un tipo que tiene algunas variantes diferentes:

fn generate_random_number() -> i32 {

    // Implementation based on https://xkcd.com/221/

    4  // Chosen by fair dice roll. Guaranteed to be random.

}


#[derive(Debug)]

enum CoinFlip {

    Heads,

    Tails,

}


fn flip_coin() -> CoinFlip {

    let random_number = generate_random_number();

    if random_number % 2 == 0 {

        return CoinFlip::Heads;

    } else {

        return CoinFlip::Tails;

    }

}


fn main() {

    println!("You got: {:?}", flip_coin());

}


  • Las enumeraciones le permiten recopilar un conjunto de valores bajo un tipo
  • Este ejemplo ofrece un tipo de enumeración CoinFlip con dos variantes Cara y Cruz. (CoinFlip::Heads y CoinFlip::Tails)
  • Este podría ser un buen momento para comparar Structs y Enums:
    • En ambos, puede tener una versión simple sin campos (estructura de unidad) o una con diferentes tipos de campos (cargas de variantes).
    • En ambos, las funciones asociadas se definen dentro de un bloque impl.
    • Incluso podría implementar las diferentes variantes de una enumeración con estructuras separadas, pero entonces no serían del mismo tipo que si estuvieran todas definidas en una enumeración.

lunes, 14 de agosto de 2023

Constructor en Rust

 


Si ya tiene variables con los nombres correctos, puede crear la estructura usando una abreviatura:

#[derive(Debug)]

struct Person {

    name: String,

    age: u8,

}


impl Person {

    fn new(name: String, age: u8) -> Person {

        Person { name, age }

    }

}


fn main() {

    let peter = Person::new(String::from("Peter"), 27);

    println!("{peter:?}");

}


Podría escribirse usando Self como tipo, ya que es intercambiable con el nombre del tipo de estructura

#[derive(Debug)]

struct Person {

    name: String,

    age: u8,

}

impl Person {

    fn new(name: String, age: u8) -> Self {

        Self { name, age }

    }

}

Podemos tambien definir los campos por defecto: 


#[derive(Debug)]

struct Person {

    name: String,

    age: u8,

}

impl Default for Person {

    fn default() -> Person {

        Person {

            name: "Bot".to_string(),

            age: 0,

        }

    }

}

fn create_default() {

    let tmp = Person {

        ..Person::default()

    };

    let tmp = Person {

        name: "Sam".to_string(),

        ..Person::default()

    };

}


  • Los métodos se definen en el bloque impl.


sábado, 12 de agosto de 2023

Tuple Structs en Rust


Si los nombres de los campos no son importantes, puede usar una estructura de tupla:


struct Point(i32, i32);

fn main() {

    let p = Point(17, 23);

    println!("({}, {})", p.0, p.1);

}


Esto se usa a menudo para envoltorios de un solo campo:


struct PoundsOfForce(f64);

struct Newtons(f64);


fn compute_thruster_force() -> PoundsOfForce {

    todo!("Ask a rocket scientist at NASA")

}


fn set_thruster_force(force: Newtons) {

    // ...

}


fn main() {

    let force = compute_thruster_force();

    set_thruster_force(force);

}

Los tipos nuevos son una excelente manera de codificar información adicional sobre el valor en un tipo primitivo, por ejemplo:
  • El número se mide en algunas unidades: Newtons en el ejemplo anterior.
  • El valor pasó cierta validación cuando se creó, por lo que ya no tendrá que volver a validarlo cada vez que lo use

viernes, 11 de agosto de 2023

Structs en Rust

 


Al igual que C y C++, Rust tiene soporte para estructuras:


struct Person {

    name: String,

    age: u8,

}


fn main() {

    let mut peter = Person {

        name: String::from("Peter"),

        age: 27,

    };

    println!("{} is {} years old", peter.name, peter.age);

    

    peter.age = 28;

    println!("{} is {} years old", peter.name, peter.age);

    

    let jackie = Person {

        name: String::from("Jackie"),

        ..peter

    };

    println!("{} is {} years old", jackie.name, jackie.age);

}

Las estructuras funcionan como en C o C++.

  • Al igual que en C++, ya diferencia de C, no se necesita typedef para definir un tipo.
  • A diferencia de C++, no hay herencia entre estructuras.
  • Los métodos se definen en un bloque impl, que veremos más adelante.
  • Este puede ser un buen momento para que la gente sepa que hay diferentes tipos de estructuras.
  • Estructuras de tamaño cero, por ejemplo, struct Foo; podría usarse al implementar un rasgo en algún tipo pero no tiene ningún dato que desee almacenar en el valor mismo.
  • Ls estructuras Tuple, que se utilizan cuando los nombres de los campos no son importantes.
  • La sintaxis ..peter nos permite copiar la mayoría de los campos de la estructura anterior sin tener que escribirlos todos explícitamente. Siempre debe ser el último elemento.

¿Cómo promover experiencias de datos?

 

 Me llego este mail de google cloud y lo quiero compartir con ustedes: 

jueves, 10 de agosto de 2023

Tiempos de vida en estructuras de datos


 Si un tipo de datos almacena datos prestados, debe anotarse con un tiempo de vida:

#[derive(Debug)]

struct Highlight<'doc>(&'doc str);


fn erase(text: String) {

    println!("Bye {text}!");

}


fn main() {

    let text = String::from("The quick brown fox jumps over the lazy dog.");

    let fox = Highlight(&text[4..19]);

    let dog = Highlight(&text[35..43]);

    // erase(text);

    println!("{fox:?}");

    println!("{dog:?}");

}


Si corremos esto: 

$ cargo run

   Compiling hello_cargo v0.1.0 (/home/emanuel/Projects/rust/hello_cargo)

warning: function `erase` is never used

 --> src/main.rs:7:4

  |

7 | fn erase(text: String) {

  |    ^^^^^

  |

  = note: `#[warn(dead_code)]` on by default


warning: `hello_cargo` (bin "hello_cargo") generated 1 warning

    Finished dev [unoptimized + debuginfo] target(s) in 1.80s

     Running `target/debug/hello_cargo`

Highlight("quick brown fox")

Highlight("lazy dog")

Pero si descomentamos esta linea // erase(text); y corremos:

$ cargo run

   Compiling hello_cargo v0.1.0 

error[E0505]: cannot move out of `text` because it is borrowed

  --> src/main.rs:19:11

   |

15 |     let fox = Highlight(&text[4..19]);

   |                          ---- borrow of `text` occurs here

...

19 |     erase(text);

   |           ^^^^ move out of `text` occurs here

20 |

21 |     println!("{fox:?}");

   |                --- borrow later used here


For more information about this error, try `rustc --explain E0505`.

error: could not compile `hello_cargo` due to previous error

  • En el ejemplo anterior, la anotación en Highlight impone que los datos subyacentes al &str contenido vivan al menos tanto tiempo como cualquier instancia de Highlight que use esos datos.
  • Si el texto se consume antes del final de la vida útil del fox (o del dog), el comprobador de préstamos arroja un error.
  • Los tipos con datos prestados obligan a los usuarios a conservar los datos originales. Esto puede ser útil para crear vistas ligeras, pero generalmente las hace un poco más difíciles de usar.
  • Cuando sea posible, haga que las estructuras de datos sean propietarias de sus datos directamente.
  • Algunas estructuras con múltiples referencias internas pueden tener más de una anotación de por vida. Esto puede ser necesario si existe la necesidad de describir las relaciones de duración entre las propias referencias, además de la duración de la estructura en sí. Esos son casos de uso muy avanzados.

Simplificando la Construcción de Imágenes con Paketo


Paketo es un proyecto de código abierto que tiene como objetivo simplificar el proceso de construcción y empaquetado de imágenes de contenedor. Ofrece un enfoque más moderno y eficiente en comparación con los enfoques tradicionales de Dockerfile. Paketo se basa en principios de mejores prácticas y utiliza lenguajes de construcción específicos para diferentes lenguajes de programación, lo que facilita la creación de imágenes de contenedor optimizadas y seguras.

  • Paquetes de Lenguaje Específico: Paketo proporciona paquetes de lenguaje específico que contienen todos los elementos necesarios para construir y ejecutar una aplicación en contenedor. Esto elimina la necesidad de configuraciones largas en Dockerfile y asegura que las imágenes sean consistentes y eficientes.
  • Detección Automática de Dependencias: Paketo tiene la capacidad de detectar automáticamente las dependencias de tu aplicación, como bibliotecas y herramientas, y agregarlas a la imagen de contenedor. Esto simplifica la gestión de dependencias y reduce la posibilidad de errores.
  • Actualizaciones de Seguridad Automáticas: Paketo ofrece actualizaciones automáticas de seguridad para las dependencias y capas de la imagen. Esto garantiza que las imágenes de contenedor estén siempre actualizadas y protegidas contra vulnerabilidades conocidas.
  • Compatibilidad Multiplataforma: Las imágenes de contenedor construidas con Paketo son compatibles con múltiples plataformas, lo que permite la implementación en diversos entornos sin preocuparse por la compatibilidad.
  • Configuración Desacoplada: A diferencia de los Dockerfiles monolíticos, Paketo promueve la configuración desacoplada mediante capas, lo que facilita la reutilización y el mantenimiento del código.


Instalación de Paketo: La instalación de Paketo es sencilla y depende del lenguaje de programación que utilices. Sigue las instrucciones en la documentación oficial para instalar la CLI de Paketo y los paquetes necesarios.

Construcción de Imágenes: Para construir una imagen de contenedor con Paketo, dirígete al directorio de tu proyecto y utiliza el comando correspondiente al paquete de lenguaje que estás utilizando. Por ejemplo, para Java:


pack build my-java-app --builder paketobuildpacks/builder:base


Este comando construirá una imagen de contenedor para tu aplicación Java.

Despliegue y Distribución: Una vez construida la imagen, puedes distribuirla en tu plataforma de elección, como Kubernetes o Docker Swarm. Las imágenes de contenedor construidas con Paketo son portables y compatibles con una variedad de entornos.

Paketo ha revolucionado la forma en que empaquetamos y distribuimos aplicaciones en contenedores. Su enfoque en paquetes de lenguaje específico, detección automática de dependencias y actualizaciones de seguridad automáticas simplifican significativamente el proceso de construcción y mantenimiento de imágenes de contenedor. Si buscas una forma más eficiente y segura de empaquetar tus aplicaciones, Paketo es una herramienta que definitivamente vale la pena explorar. Su impacto en la productividad y la seguridad en el desarrollo y la implementación de software es innegable.

Dejo link : https://paketo.io/



Duración de las llamadas a funciones en Rust

 


Además de tomar prestados sus argumentos, una función puede devolver un valor prestado:

#[derive(Debug)]

struct Point(i32, i32);


fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {

    if p1.0 < p2.0 { p1 } else { p2 }

}


fn main() {

    let p1: Point = Point(10, 10);

    let p2: Point = Point(20, 20);

    let p3: &Point = left_most(&p1, &p2);

    println!("left-most point: {:?}", p3);

}

  • 'a es un parámetro genérico, lo infiere el compilador.
  • Los tiempos de vida comienzan con ' y 'a es un nombre predeterminado típico.
  • Lea &'a Point como “un Punto prestado que es válido por lo menos durante el tiempo de vida a”.
  • La parte al menos es importante cuando los parámetros están en diferentes ámbitos.

En el ejemplo anterior, intente lo siguiente:

Mueva la declaración de p2 y p3 a un nuevo ámbito ({ ... }), lo que da como resultado el siguiente código:

#[derive(Debug)]

struct Point(i32, i32);


fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {

    if p1.0 < p2.0 { p1 } else { p2 }

}


fn main() {

    let p1: Point = Point(10, 10);

    let p3: &Point;

    {

        let p2: Point = Point(20, 20);

        p3 = left_most(&p1, &p2);

    }

    println!("left-most point: {:?}", p3);

}


Esto no compila ya que p3 sobrevive a p2.

Restablezca el espacio de trabajo y cambie la firma de la función a fn left_most<'a, 'b>(p1: &'a Point, p2: &'a Point) -> &'b Point. Esto no se compilará porque la relación entre las vidas 'a y 'b no está clara.

Otra forma de explicarlo:

  • Una función toma prestadas dos referencias a dos valores y la función devuelve otra referencia.
  • Debe haber venido de una de esas dos entradas (o de una variable global).
  • ¿Cuál es? El compilador necesita saber, por lo que en el sitio de la llamada, la referencia devuelta no se usa por más tiempo que una variable de donde proviene la referencia.

miércoles, 9 de agosto de 2023

Veamos Pedestal y Clojure


Clojure es un lenguaje de programación funcional y dinámico que se ejecuta en la máquina virtual de Java (JVM). Diseñado para ser simple, eficiente y expresivo, Clojure se basa en los principios de la programación funcional y proporciona herramientas para manejar la concurrencia y la inmutabilidad de manera efectiva. Su sintaxis concisa y su énfasis en la inmutabilidad lo convierten en una excelente elección para construir aplicaciones robustas y escalables.

Pedestal es un framework web desarrollado en Clojure que se enfoca en la construcción de aplicaciones web escalables y de alto rendimiento. A diferencia de algunos otros frameworks web, Pedestal no se basa en el paradigma de controladores y vistas, sino que se centra en la manipulación de datos y el flujo de información. Esto lo convierte en una opción ideal para aplicaciones modernas que requieren manejo eficiente de datos en tiempo real.

Las caracteristicas claves son: 

  • Modelo de Manejo de Datos: Pedestal se basa en el modelo de manejo de datos (data-driven) en lugar del enfoque tradicional de controladores y vistas. Esto permite una manipulación más eficiente y coherente de los datos a medida que fluyen a través de la aplicación.
  • Componentes Reutilizables: El framework fomenta la creación de componentes reutilizables que pueden ser ensamblados fácilmente para construir aplicaciones complejas. Esto mejora la modularidad y el mantenimiento del código.
  • Enfoque Asincrónico: Pedestal está diseñado para manejar concurrencia y operaciones asincrónicas de manera efectiva. Esto es esencial para aplicaciones que necesitan manejar múltiples solicitudes y actualizaciones en tiempo real.
  • Rendimiento Optimizado: Gracias a su enfoque asincrónico y a la optimización para el manejo eficiente de datos, Pedestal es capaz de ofrecer un alto rendimiento incluso en situaciones de alta carga.


La integración de Pedestal con Clojure es perfectamente natural, ya que ambos comparten la misma plataforma de ejecución (JVM) y una filosofía similar centrada en la simplicidad y la eficiencia. Al aprovechar las capacidades funcionales de Clojure, Pedestal puede manejar de manera elegante la manipulación de datos y el flujo de información en las aplicaciones web.


Vamos a hacer un hola mundo, para ello vamos a crear el proyecto con Leiningen : 


lein new pedestal-app hello-world


Esto creará una estructura de proyecto básica en el directorio hello-world.


Ejecutamos :

lein run

El servidor Pedestal se ejecutará en el puerto 8080 por defecto. Abre tu navegador web y navega a http://localhost:8080. Deberías ver el mensaje "¡Hola, Mundo desde Pedestal y Clojure!" en la página.

Dejo link: https://github.com/pedestal/pedestal

sábado, 5 de agosto de 2023

Préstamos compartidos y únicos

 Rust impone restricciones en las formas en que puede tomar prestados valores:

  • Puede tener uno o más valores &T en un momento dado, o
  • Puede tener exactamente un valor de &mut T.
Por ejemplo: 

fn main() {
    let mut a: i32 = 10;
    let b: &i32 = &a;

    {
        let c: &mut i32 = &mut a;
        *c = 20;
    }

    println!("a: {a}");
    println!("b: {b}");
}

Si tratamos de correr este programa: 

$ cargo run
   Compiling hello_cargo v0.1.0 
error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable
  --> src/main.rs:6:27
   |
3  |     let b: &i32 = &a;
   |                   -- immutable borrow occurs here
...
6  |         let c: &mut i32 = &mut a;
   |                           ^^^^^^ mutable borrow occurs here
...
11 |     println!("b: {b}");
   |                   - immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `hello_cargo` due to previous error

El código anterior no compila porque a se toma prestado como mutable (a través de c) e inmutable (a través de b) al mismo tiempo.
¡

miércoles, 2 de agosto de 2023

Borrowing en Rust


En lugar de transferir la propiedad al llamar a una función, puede dejar que una función tome prestado el valor:


#[derive(Debug)]

struct Point(i32, i32);


fn add(p1: &Point, p2: &Point) -> Point {

    Point(p1.0 + p2.0, p1.1 + p2.1)

}


fn main() {

    let p1 = Point(3, 4);

    let p2 = Point(10, 20);

    let p3 = add(&p1, &p2);

    println!("{p1:?} + {p2:?} = {p3:?}");

}


  • La función de add toma prestados dos puntos y devuelve un nuevo punto.
  • La persona que llama conserva la propiedad de las entradas.
  • El compilador de Rust puede realizar la optimización del valor de retorno (RVO).
  • En C++, la elisión de copia debe definirse en la especificación del lenguaje porque los constructores pueden tener efectos secundarios. En Rust, esto no es un problema en absoluto. Si RVO no sucedió, Rust siempre realizará una copia memcpy simple y eficiente.