Translate

jueves, 14 de septiembre de 2023

Prueba Erlang


Quiero recomendarles el tutorial tryerlang que encontre de casualidad. Si bien es basico, es muy interactivo y esta bueno. 

Dejo link: https://www.tryerlang.org/

Box en Rust parte 2


Y siguiendo con Box, los tipos de datos recursivos o tipos de datos con tamaños dinámicos necesitan usar un Box:

#[derive(Debug)]

enum List<T> {

    Cons(T, Box<List<T>>),

    Nil,

}


fn main() {

    let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));

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

}

Si no se usaba Box e intentábamos incrustar una Lista directamente en la Lista, el compilador no calcularía un tamaño fijo de la estructura en la memoria (la Lista sería de tamaño infinito).

Box resuelve este problema ya que tiene el mismo tamaño que un puntero normal y solo apunta al siguiente elemento de la Lista.

Veamos que pasa si lo eliminamos: 

enum List<T> {

    Cons(T, List<T>),

    Nil,

}


fn main() {

    let list: List<i32> = List::Cons(1, List::Cons(2, List::Nil));

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

}

Y si ejecutamos esto: 

cargo run

   Compiling hello_cargo v0.1.0 

error[E0072]: recursive type `List` has infinite size

 --> src/main.rs:2:1

  |

2 | enum List<T> {

  | ^^^^^^^^^^^^

3 |     Cons(T, List<T>),

  |             ------- recursive without indirection

  |

help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle

  |

3 |     Cons(T, Box<List<T>>),

  |             ++++       +


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

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


Un Box no puede estar vacío, por lo que el puntero siempre es válido y no nulo. Esto permite al compilador optimizar el diseño de la memoria.

sábado, 9 de septiembre de 2023

Como crear un nuevo proyecto con Clojure y Leiningen?



Bueno, todo tiene un principio y vamos a empezar a crear un proyectito de consola con Clojure y Leiningen

$ lein new app my-project

Fijate vos que si queres utilizar nombre de proyecto con mayuscula, no te deja, ojo ahi. 

Ahora vamos a ejecutarlo :

$ lein run

podemos generar un jar con : 

$ lein jar

Si estamos trabajando en un proyecto de aplicación, Leiningen nos brinda la posibilidad de construir lo que se llama un uberjar. Este es un archivo JAR que contiene el proyecto en sí y todas las dependencias y está configurado para permitir que se ejecute tal cual.

$ lein uberjar

Compiling secuencia-clojure.core

$ java -jar target/uberjar/el-jar-standalone.jar 

Y ya podemos empezar!!

viernes, 8 de septiembre de 2023

Box en Rust


Box es un puntero a los datos del monticulo:

fn main() {

    let five = Box::new(5);

    println!("five: {}", *five);

}

Box<T> implementa Deref<Target = T>, lo que significa que puedes llamar métodos desde T directamente en un Box<T>.

Box es como std::unique_ptr en C++, excepto que se garantiza que el elemento no será nulo.

En el ejemplo anterior, incluso podemos omitir el * en println! gracias a Deref.

Un Box puede resultar útil cuando:

  • tiene un tipo cuyo tamaño no se puede conocer en el momento de la compilación, pero el compilador de Rust quiere saber un tamaño exacto.
  • desea transferir una propiedad de una gran cantidad de datos. Para evitar copiar grandes cantidades de datos en la pila, almacene los datos en el monticulo en un Box de modo que solo se mueva el puntero.

lunes, 4 de septiembre de 2023

HashMap en Rust


Veamos un ejemplo: 


use std::collections::HashMap;

fn main() {

    let mut page_counts = HashMap::new();

    page_counts.insert("Adventures of Huckleberry Finn".to_string(), 207);

    page_counts.insert("Grimms' Fairy Tales".to_string(), 751);

    page_counts.insert("Pride and Prejudice".to_string(), 303);


    if !page_counts.contains_key("Les Misérables") {

        println!("We know about {} books, but not Les Misérables.",

                 page_counts.len());

    }


    for book in ["Pride and Prejudice", "Alice's Adventure in Wonderland"] {

        match page_counts.get(book) {

            Some(count) => println!("{book}: {count} pages"),

            None => println!("{book} is unknown.")

        }

    }


    // Use the .entry() method to insert a value if nothing is found.

    for book in ["Pride and Prejudice", "Alice's Adventure in Wonderland"] {

        let page_count: &mut i32 = page_counts.entry(book.to_string()).or_insert(0);

        *page_count += 1;

    }


    println!("{page_counts:#?}");

}


Si ejecutamos este programa: 

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

     Running `target/debug/hello_cargo`

We know about 3 books, but not Les Misérables.

Pride and Prejudice: 303 pages

Alice's Adventure in Wonderland is unknown.

{

    "Pride and Prejudice": 304,

    "Grimms' Fairy Tales": 751,

    "Adventures of Huckleberry Finn": 207,

    "Alice's Adventure in Wonderland": 1,

}


HashMap no está definido por defecto y es necesario incluirlo : use std::collections::HashMap;

Desde Rust 1.56, HashMap implementa From<[(K, V); N]>, que nos permite inicializar fácilmente un mapa hash a partir de una matriz literal:

  let page_counts = HashMap::from([

    ("Harry Potter and the Sorcerer's Stone".to_string(), 336),

    ("The Hunger Games".to_string(), 374),

  ]);

Alternativamente, HashMap se puede construir a partir de cualquier iterador que produzca tuplas de valores clave.

Mostramos HashMap<String, i32> y evitamos usar &str como clave para facilitar los ejemplos. Por supuesto, se puede utilizar referencias en colecciones, pero puede generar complicaciones con el verificador de préstamos.

Podemos agregar estas lineas : 

  let pc1 = page_counts

      .get("Harry Potter and the Sorcerer's Stone ")

      .unwrap_or(&336);

  let pc2 = page_counts

      .entry("The Hunger Games".to_string())

      .or_insert(374);

La primera línea verá si un libro está en el HashMap y, en caso contrario, devolverá un valor alternativo. La segunda línea insertará el valor alternativo en el HashMap si no se encuentra el libro.

 


Vec en Rust


Vec es el búfer estándar de tamaño variable de Rust, veamos un ejemplo:


fn main() {

    let mut v1 = Vec::new();

    v1.push(42);

    println!("v1: len = {}, capacity = {}", v1.len(), v1.capacity());


    let mut v2 = Vec::with_capacity(v1.len() + 1);

    v2.extend(v1.iter());

    v2.push(9999);

    println!("v2: len = {}, capacity = {}", v2.len(), v2.capacity());


    // Canonical macro to initialize a vector with elements.

    let mut v3 = vec![0, 0, 1, 2, 3, 4];


    // Retain only the even elements.

    v3.retain(|x| x % 2 == 0);

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


    // Remove consecutive duplicates.

    v3.dedup();

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

}


Vec implementa Deref<Target = [T]>, lo que significa que puedes llamar a métodos de slice.

  • Vec es un tipo de colección, junto con String y HashMap. Los datos que contiene se almacenan en el monticulo. Esto significa que no es necesario conocer la cantidad de datos en el momento de la compilación. Puede crecer o reducirse en tiempo de ejecución.
  • Observe que Vec<T> también es un tipo genérico, pero no es necesario especificar T explícitamente. Como siempre con la inferencia de tipo Rust, la T se estableció durante la primera llamada push.
  • vec![...] es una macro canónica para usar en lugar de Vec::new() y admite agregar elementos iniciales al vector.
  • Para indexar el vector se puede utilizar [], pero entrarán en pánico si están fuera de los límites. Alternativamente, usar get devolverá un Option. La función pop eliminará el último elemento.

domingo, 3 de septiembre de 2023

String en Rust


 String es el búfer de cadena UTF-8 estándar:


fn main() {

    let mut s1 = String::new();

    s1.push_str("Hello");

    println!("s1: len = {}, capacity = {}", s1.len(), s1.capacity());


    let mut s2 = String::with_capacity(s1.len() + 1);

    s2.push_str(&s1);

    s2.push('!');

    println!("s2: len = {}, capacity = {}", s2.len(), s2.capacity());


    let s3 = String::from("🇨🇭");

    println!("s3: len = {}, number of chars = {}", s3.len(),

             s3.chars().count());

}


Si ejecutamos este código: 


Compiling hello_cargo v0.1.0 

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

     Running `target/debug/hello_cargo`

s1: len = 5, capacity = 8

s2: len = 6, capacity = 6

s3: len = 8, number of chars = 2

String implementa Deref<Target = str>, lo que significa que puedes llamar a todos los métodos str en un String.

  • String::new devuelve una nueva cadena vacía, se usa String::with_capacity cuando se sabe cuántos caracteres tiene la cadena.
  • String::len devuelve el tamaño de la cadena en bytes (que puede ser diferente de su longitud en caracteres).
  • String::chars devuelve un iterador sobre los caracteres reales. Un carácter puede ser diferente de lo que un humano considerará un "carácter" debido a los grupos de grafemas.
  • Cuando las personas se refieren a cadenas, podrían estar hablando de &str o String.
  • Cuando un tipo implementa Deref<Target = T>, el compilador le permitirá llamar de forma transparente a métodos desde T.
  • String implementa Deref<Target = str> que le da acceso de forma transparente a los métodos de str.
  • String se implementa como un contenedor alrededor de un vector de bytes; muchas de las operaciones que ve admitidas en vectores también se admiten en String, pero con algunas garantías adicionales.


sábado, 2 de septiembre de 2023

Rust Standard Library


Rust tiene una biblioteca estándar que ayuda a establecer un conjunto de tipos comunes utilizados por las bibliotecas y los programas de Rust. De esta manera, dos bibliotecas pueden funcionar juntas sin problemas porque ambas usan el mismo tipo de cadena, por ejemplo.

Los tipos de vocabulario comunes incluyen:

  • Option y Result: se utilizan para valores opcionales y manejo de errores.
  • String: el tipo de cadena predeterminado utilizado para los datos propios.
  • Vec: un vector extensible estándar.
  • HashMap: un tipo de mapa hash con un algoritmo hash configurable.
  • Box: un puntero propio para datos asignados al monticulo.
  • Rc: un puntero compartido.

De hecho, Rust contiene varias capas de la biblioteca estándar: core, alloc y std.

core incluye los tipos y funciones más básicos que no dependen de libc, asignador o incluso de la presencia de un sistema operativo.

alloc incluye tipos que requieren un asignador de monticulo global, como Vec, Box y Arc.

Option y Result en Rust


Los tipos representan datos opcionales:


fn main() {

    let numbers = vec![10, 20, 30];

    let first: Option<&i8> = numbers.first();

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


    let idx: Result<usize, usize> = numbers.binary_search(&10);

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

}

Si ejecuto este codigo : 

cargo run

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

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

     Running `target/debug/hello_cargo`

first: Some(10)

idx: Ok(0)


Si por ejemplo busco el 39 : 

    let idx: Result<usize, usize> = numbers.binary_search(&39); 

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


Si corremos esto : 

cargo run

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

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

     Running `target/debug/hello_cargo`

first: Some(10)

idx: Err(3)

El resultado es Err y no Ok. 

  • Option y Result se utilizan ampliamente no solo en la biblioteca estándar.
  • La Option <&T> tiene cero espacio adicional en comparación con &T.
  • El resultado es el tipo estándar para implementar el manejo de errores.
  • binario_search devuelve Result<usize, usize>.
    • Si se encuentra, Result::Ok contiene el índice donde se encuentra el elemento.
    • De lo contrario, Result::Err contiene el índice donde se debe insertar dicho elemento.

viernes, 1 de septiembre de 2023

Metodos en Rust parte 3


Veamos un ejemplo de metodos:

#[derive(Debug)]

struct Race {

    name: String,

    laps: Vec<i32>,

}


impl Race {

    fn new(name: &str) -> Race {  // No receiver, a static method

        Race { name: String::from(name), laps: Vec::new() }

    }


    fn add_lap(&mut self, lap: i32) {  // Exclusive borrowed read-write access to self

        self.laps.push(lap);

    }


    fn print_laps(&self) {  // Shared and read-only borrowed access to self

        println!("Recorded {} laps for {}:", self.laps.len(), self.name);

        for (idx, lap) in self.laps.iter().enumerate() {

            println!("Lap {idx}: {lap} sec");

        }

    }


    fn finish(self) {  // Exclusive ownership of self

        let total = self.laps.iter().sum::<i32>();

        println!("Race {} is finished, total lap time: {}", self.name, total);

    }

}


fn main() {

    let mut race = Race::new("Monaco Grand Prix");

    race.add_lap(70);

    race.add_lap(68);

    race.print_laps();

    race.add_lap(71);

    race.print_laps();

    race.finish();

    // race.add_lap(42);

}

Lo ejecutamos : 

cargo run

   Compiling hello_cargo v0.1.0 

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

     Running `target/debug/hello_cargo`

Recorded 2 laps for Monaco Grand Prix:

Lap 0: 70 sec

Lap 1: 68 sec

Recorded 3 laps for Monaco Grand Prix:

Lap 0: 70 sec

Lap 1: 68 sec

Lap 2: 71 sec

Race Monaco Grand Prix is finished, total lap time: 209


Los cuatro métodos aquí utilizan un receptor de método diferente.

Si intentamos llamar a finalizar dos veces o descomentamos // race.add_lap(42); , lanza este error : 

cargo run

   Compiling hello_cargo v0.1.0 

error[E0382]: borrow of moved value: `race`

  --> src/main.rs:37:5

   |

30 |     let mut race = Race::new("Monaco Grand Prix");

   |         -------- move occurs because `race` has type `Race`, which does not implement the `Copy` trait

...

36 |     race.finish();

   |          -------- `race` moved due to this method call

37 |     race.add_lap(42);

   |     ^^^^^^^^^^^^^^^^ value borrowed here after move

   |

note: this function takes ownership of the receiver `self`, which moves `race`

  --> src/main.rs:23:15

   |

23 |     fn finish(self) {  // Exclusive ownership of self

   |               ^^^^

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

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

Y es porque finish toma todo el control del registro. 

Tenga en cuenta que, aunque los receptores de métodos son diferentes, las funciones no estáticas se denominan de la misma manera en el cuerpo principal. Rust permite la referencia y desreferenciación automática al llamar a métodos. Rust agrega automáticamente los cambios &, *, para que ese objeto coincida con la firma del método.

Ebook: Estos 4 patrones van a modernizar tu estrategia multinube

 Me llego este mail y quería compartirlo: 

Las empresas modernas eligen Oracle Cloud Infrastructure (OCI)

En este ebook te contamos las razones
Conoce cómo las empresas crean y ejecutan aplicaciones seguras y escalables gracias a la nube de Oracle.

martes, 29 de agosto de 2023

Metodos en Rust parte 2


Veamos este código: 

#[derive(Debug)]

struct Person {

    name: String,

    age: u8,

}


impl Person {

    fn say_hello(&self) {

        println!("Hello, my name is {}", self.name);

    }

}


fn main() {

    let peter = Person {

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

        age: 27,

    };

    peter.say_hello();

}

El &self del post anterior indica que el método toma prestado el objeto de forma inmutable. Hay otros posibles receptores para un método:

  • &self: toma prestado el objeto de tipo Person que llama utilizando una referencia compartida e inmutable. El objeto se puede volver a utilizar posteriormente.
  • &mut self: toma prestado el objeto de tipo Person que llama utilizando una referencia única y mutable. El objeto se puede volver a utilizar posteriormente.
  • self: toma posesión del objeto. El método se convierte en propietario del objeto. El objeto se eliminará (desasignará) cuando el método regrese, a menos que su propiedad se transmita explícitamente. La propiedad total no significa automáticamente mutabilidad.
  • mut self: igual que el anterior, pero el método puede mutar el objeto.
  • Sin receptor: esto se convierte en un método estático en la estructura. Normalmente se utiliza para crear constructores que se denominan new por convención.

Más allá de las variantes de self, también hay tipos de contenedores especiales que pueden ser tipos de receptores, como Box<Self>.

Estas restricciones siempre se juntan en Rust debido a las reglas del verificador prestado, y self no es una excepción. No es posible hacer referencia a una estructura desde múltiples ubicaciones y llamar a un método mutante (&mut self) en ella.

viernes, 25 de agosto de 2023

Metodos en Rust

 


Rust te permite asociar funciones con tus nuevos tipos. Hacemos esto con un bloque impl:

#[derive(Debug)]

struct Person {

    name: String,

    age: u8,

}


impl Person {

    fn say_hello(&self) {

        println!("Hello, my name is {}", self.name);

    }

}


fn main() {

    let peter = Person {

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

        age: 27,

    };

    peter.say_hello();

}

Los métodos se llaman en una instancia de un tipo (como una estructura o enumeración), el primer parámetro representa la instancia como self.

Los desarrolladores pueden optar por utilizar métodos para aprovechar la sintaxis del receptor de métodos y ayudar a mantenerlos más organizados. Al utilizar métodos, podemos mantener todo el código de implementación en un lugar predecible.

self es un término abreviado y es de tipo &Person, por lo tanto podemos escribir esto como : 

impl Person {

    fn say_hello(self : &Person) {

        println!("Hello, my name is {}", self.name);

    }

}


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