Translate

domingo, 2 de julio de 2023

Rustdoc


Todos los elementos de Lenguaje Rust se pueden documentar usando una sintaxis especial ///.

/// Determine whether the first argument is divisible by the second argument.

///

/// If the second argument is zero, the result is false.

fn is_divisible_by(lhs: u32, rhs: u32) -> bool {

    if rhs == 0 {

        return false;  // Corner case, early return

    }

    lhs % rhs == 0     // The last expression in a block is the return value

}


Los contenidos se tratan como Markdown. Las librerias de Rust se documentan automáticamente en docs.rs mediante la herramienta rustdoc. Es idiomático documentar todos los elementos públicos en una API utilizando este patrón.

Y para utilizarla podemos hacer : 

rustdoc src/main.rs 



sábado, 1 de julio de 2023

Funciones en Rust



Una versión de Rust de la famosa pregunta de entrevista de FizzBuzz:

fn main() {

    print_fizzbuzz_to(20);

}


fn is_divisible(n: u32, divisor: u32) -> bool {

    if divisor == 0 {

        return false;

    }

    n % divisor == 0

}


fn fizzbuzz(n: u32) -> String {

    let fizz = if is_divisible(n, 3) { "fizz" } else { "" };

    let buzz = if is_divisible(n, 5) { "buzz" } else { "" };

    if fizz.is_empty() && buzz.is_empty() {

        return format!("{n}");

    }

    format!("{fizz}{buzz}")

}


fn print_fizzbuzz_to(n: u32) {

    for i in 1..=n {

        println!("{}", fizzbuzz(i));

    }

}


$ cargo run

   Compiling hello_cargo v0.1.0 

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

     Running `target/debug/hello_cargo`

1

2

fizz

4

buzz

fizz

7

8

fizz

buzz

11

fizz

13

14

fizzbuzz

16

17

fizz

19

buzz


Los parámetros de declaración son seguidos por un tipo (lo contrario de algunos lenguajes de programación), luego un tipo de retorno.

La última expresión en el cuerpo de una función (o cualquier bloque) se convierte en el valor devuelto. Y Simplemente se omite el ; al final de la expresión.

Algunas funciones no tienen valor de retorno y devuelven el 'tipo de unidad', (). El compilador inferirá esto si se omite el tipo de retorno -> ().

La expresión de rango en el ciclo for en print_fizzbuzz_to() contiene =n, lo que hace que incluya el límite superior.

Rust: String vs str

 


Dado este post, podemos entender los dos tipos de cadenas en Rust:

fn main() {

    let s1: &str = "World";

    println!("s1: {s1}");


    let mut s2: String = String::from("Hello ");

    println!("s2: {s2}");

    s2.push_str(s1);

    println!("s2: {s2}");

    

    let s3: &str = &s2[6..];

    println!("s3: {s3}");

}

$ cargo run

   Compiling hello_cargo v0.1.0 

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

     Running `target/debug/hello_cargo`

s1: World

s2: Hello 

s2: Hello World

s3: World


En Rust: 

  • &str una referencia inmutable a un segmento de cadena.
  • String de un búfer de cadena mutable.

&str introduce un segmento de cadena, que es una referencia inmutable a datos de cadena codificados en UTF-8 almacenados en un bloque de memoria. Los literales de cadena ("Hola") se almacenan en el binario del programa.

El tipo String de Rust es un contenedor alrededor de un vector de bytes. Al igual que con un Vec<T>, es propiedad.

Como ocurre con muchos otros tipos, String::from() crea una cadena a partir de un literal de cadena; String::new() crea una nueva cadena vacía, a la que se pueden agregar datos de cadena usando los métodos push() y push_str().

La macro format!() es una forma conveniente de generar una cadena propia a partir de valores dinámicos. Acepta la misma especificación de formato que println!().

Puede tomar prestados segmentos de &str de String a través de & y, opcionalmente, selección de rango.

Para programadores de C++: piense en &str como const char* de C++, pero el que siempre apunta a una cadena válida en la memoria. Rust String es un equivalente aproximado de std::string de C++ (diferencia principal: solo puede contener bytes codificados en UTF-8 y nunca utilizará una optimización de cadena pequeña).

jueves, 29 de junio de 2023

Slices en Rust


Un segmento o slices te da una vista de una colección más grande:

 fn main() {

    let a: [i32; 6] = [10, 20, 30, 40, 50, 60];

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


    let s: &[i32] = &a[2..4];

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

}

$ cargo run

   Compiling hello_cargo v0.1.0 

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

     Running `target/debug/hello_cargo`

a: [10, 20, 30, 40, 50, 60]

s: [30, 40]


Creamos un segmento a partir de un arreglo y especificando los índices inicial y final entre paréntesis.

Si el segmento comienza en el índice 0, la sintaxis de rango de Rust nos permite descartar el índice inicial, lo que significa que &a[0..a.len()] y &a[..a.len()] son idénticos.

Lo mismo ocurre con el último índice, por lo que &a[2..a.len()] y &a[2..] son idénticos.

Para crear fácilmente una porción de la matriz completa, podemos usar &a[..].

s es una referencia a una porción de i32s. Y el tipo de s es &[i32] y no menciona la longitud del vector. Esto nos permite realizar cálculos en rebanadas de diferentes tamaños.

Las rebanadas siempre toman prestado de otro objeto. En este ejemplo, a tiene que permanecer "vivo" durante al menos el mismo tiempo que nuestro segmento.

La pregunta sobre la modificación de a[3] puede generar una discusión interesante, pero la respuesta es que, por razones de seguridad de la memoria, no puede hacerlo a través de a después de crear un segmento, pero puede leer los datos de a y s de forma segura. 


miércoles, 28 de junio de 2023

Rust y Referencias colgantes


 Rust prohibirá las referencias colgantes:


fn main() {

    let ref_x: &i32;

    {

        let x: i32 = 10;

        ref_x = &x;

    }

    println!("ref_x: {ref_x}");

}


Se dice que una referencia "toma prestado" el valor al que se refiere.

Rust está rastreando la vida útil de todas las referencias para garantizar que vivan lo suficiente. Y lanza el siguiente error: 


$ cargo run

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

error[E0597]: `x` does not live long enough

  --> src/main.rs:9:17

   |

9  |         ref_x = &x;

   |                 ^^ borrowed value does not live long enough

10 |

11 |     }

   |     - `x` dropped here while still borrowed

12 |

13 |     println!("ref_x: {ref_x}");

   |                       ----- borrow later used here


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

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


lunes, 26 de junio de 2023

Rust: Tipos de compuestos

 

TypesLiterals
Arrays[T; N][20, 30, 40][0; 3]
Tuples()(T,)(T1, T2), …()('x',)('x', 1.2), …


Asignación de matriz y acceso:

fn main() {
    let mut a: [i8; 10] = [42; 10];
    a[5] = 0;
    println!("a: {:?}", a);
}

Asignación de tuplas y acceso:

fn main() {
    let t: (i8, bool) = (7, true);
    println!("1st index: {}", t.0);
    println!("2nd index: {}", t.1);
}

Arrays:

Los Arrays tienen elementos del mismo tipo, T, y longitud, N, que es una constante de tiempo de compilación. Tenga en cuenta que la longitud de la matriz es parte de su tipo, lo que significa que [u8; 3] y [u8; 4] se consideran dos tipos diferentes.

Podemos usar literales para asignar valores a matrices.


Tuplas:

Al igual que los arreglos, las tuplas tienen una longitud fija.

Las tuplas agrupan valores de diferentes tipos en un tipo compuesto.

Se puede acceder a los campos de una tupla por el período y el índice del valor, p. t.0, t.1.

La tupla vacía () también se conoce como el "tipo de unidad". Es a la vez un tipo y el único valor válido de ese tipo, es decir, tanto el tipo como su valor se expresan como (). Se utiliza para indicar, por ejemplo, que una función o expresión no tiene valor de retorno, como veremos más adelante.

Puede considerarlo como un void que puede resultarle familiar de otros lenguajes de programación.

Referencias en Rust


Como C++, Rust tiene referencias:

fn main() {

    let mut x: i32 = 10;

    let ref_x: &mut i32 = &mut x;

    *ref_x = 20;

    println!("x: {x}");

}

Debemos desreferenciar ref_x al asignarleun valor, de forma similar a los punteros de C y C++.

Rust eliminará automáticamente la referencia en algunos casos, en particular al invocar métodos.

Las referencias que se declaran como mut se pueden vincular a diferentes valores durante su vida útil.

Asegúrese de notar la diferencia entre let mut ref_x: &i32 y let ref_x: &mut i32. El primero representa una referencia mutable que se puede vincular a diferentes valores, mientras que el segundo representa una referencia a un valor mutable.

viernes, 23 de junio de 2023

Rust: Comandos básicos y tipos


Gran parte de la sintaxis de Rust le resultará familiar de C, C++ o Java:

  • Los bloques y ámbitos están delimitados por llaves.
  • Los comentarios de línea comienzan con //, los comentarios de bloque están delimitados por /* ... */.
  • Palabras clave como if y while funcionan de la misma manera.
  • La asignación de variables se realiza con =, la comparación se realiza con ==.

Los tipos escalares son : 


TypesLiterals
Signed integersi8i16i32i64i128isize-1001_000123i64
Unsigned integersu8u16u32u64u128usize012310u16
Floating point numbersf32f643.14-10.0e202f32
Strings&str"foo""two\nlines"
Unicode scalar valueschar'a''α''∞'
Booleansbooltruefalse

Cuanto bites usan: 

iN, uN y fN tienen N bits,
isize y usize son el ancho de un puntero,
char tiene 32 bits,
bool tiene un ancho de 8 bits.

Las cadenas sin formato permite crear un valor &str con escapes deshabilitados: r"\n" == "\\n". Puede incrustar comillas dobles usando una cantidad igual de # a cada lado de las comillas:

fn main() {
    println!(r#"<a href="link.html">link</a>"#);
    println!("<a href=\"link.html\">link</a>");
}
Las cadenas de bytes le permiten crear un valor &[u8] directamente:

fn main() {
    println!("{:?}", b"abc");
    println!("{:?}", &[97, 98, 99]);
}

sábado, 17 de junio de 2023

Primeros pasos con Rust


Quiero recomendarles el sitio primeros pasos en Rust, para aprender de 0 el lenguaje Rust. La pagina dice: 

¿Está interesado en aprender un nuevo lenguaje de programación que está creciendo en uso y popularidad? ¡Empiece por aquí! Siente las bases del conocimiento que necesita para compilar programas rápidos y eficaces en Rust.

En esta ruta de aprendizaje, hará lo siguiente:

  • Instalar las herramientas necesarias para escribir sus primeras líneas de código de Rust.
  • Aprender los conceptos básicos de Rust.
  • Aprender a administrar los errores.
  • Administrar la memoria en Rust.
  • Usar tipos y rasgos genéricos.
  • Configurar módulos para paquetes y contenedores.
  • Escribir y ejecutar pruebas automatizadas.
  • Crear una herramienta de línea de comandos.

Sin más dejo link:  https://learn.microsoft.com/es-es/training/paths/rust-first-steps/

jueves, 15 de junio de 2023

Ya tenemos los resultados de la encuesta de stackoverflow

 


Como dije, ya tenemos los resultados de la encuesta de stackoverflow!!!


Dejo link: 

https://survey.stackoverflow.co/2023/

¿Por qué Rust?



Los puntos más fuertes de Rust son:

  • Seguridad de la memoria.
  • Comportamiento bien definido en tiempo de ejecución.
  • Características del lenguaje moderno.

Si lo comparamos con otros lenguajes :

Experiencia con C o C++: Rust elimina toda una clase de errores de tiempo de ejecución. Obtiene un rendimiento como en C y C++, pero no tiene los problemas de inseguridad de la memoria. Además, es un lenguaje moderno con construcciones como pattern matching y la gestión de dependencias integrada.

Experiencia con Java, Go, Python, JavaScript…: Obtiene la misma seguridad de memoria que en esos lenguajes, además de una sensación de lenguaje de alto nivel similar. Además, obtiene un rendimiento rápido y predecible como C y C++ (sin recolector de basura), así como acceso a hardware de bajo nivel (si lo necesita).

Supera 6 desafíos clave de la nube con Google Cloud.

 

Un pequeño ejemplo en Rust


Un pequeño programa de ejemplo en Rust:

fn main() {              // Program entry point

    let mut x: i32 = 6;  // Mutable variable binding

    print!("{x}");       // Macro for printing, like printf

    while x != 1 {       // No parenthesis around expression

        if x % 2 == 0 {  // Math like in other languages

            x = x / 2;

        } else {

            x = 3 * x + 1;

        }

        print!(" -> {x}");

    }

    println!();

}


Si corremos este programa: 

$ cargo run

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

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

     Running `target/debug/hello_cargo`

6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1


El código implementa la conjetura de Collatz: se cree que el ciclo siempre terminará, pero esto aún no está probado. 

Que podemos ver de este código: 

  • Todas las variables están tipadas estáticamente. Podemos eliminar i32 para activar la inferencia de tipo :  let mut x = 6; 
  • mut se utiliza para indicar que x es mutable. 
  • print! se utiliza para imprimir. 


miércoles, 14 de junio de 2023

¿Qué es Rust?


Rust es un nuevo lenguaje de programación que tuvo su versión 1.0 en 2015:

  • Rust es un lenguaje compilado estáticamente con un papel similar al de C++
    • rustc usa LLVM como backend.
  • Rust admite muchas plataformas y arquitecturas:
    • x86, ARM, WebAssembly, …
    • Linux, Mac, Windows,…
  • Rust se utiliza para una amplia gama de dispositivos:
    • firmware y cargadores de arranque,
    • pantallas inteligentes,
    • teléfonos móviles,
    • escritorios,
    • servidores.

Rust encaja en la misma área que C++:
  • Alta flexibilidad.
  • Alto nivel de control.
  • Se puede programar para dispositivos muy limitados, como teléfonos móviles.
  • No tiene runtime, ni recolección de basura.
  • Se centra en la fiabilidad y la seguridad sin sacrificar el rendimiento.
Pasemos al programa Rust más simple posible, un programa clásico de Hello World:

fn main() {
    println!("Hello 🌍!");
}

$ cargo run
   Compiling hello_cargo v0.1.0 (/home/emanuel/Projects/rust/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/hello_cargo`
Hello 🌍!

Lo que ves:
  • Las funciones se introducen con fn.
  • Los bloques están delimitados por llaves como en C y C++.
  • La función principal es el punto de entrada del programa.
  • Rust tiene macros higiénicas, println! es un ejemplo de esto.
  • Las cadenas Rust están codificadas en UTF-8 y pueden contener cualquier carácter Unicode.

Puntos clave:
  • Rust es muy parecido a otros lenguajes en la tradición C/C++/Java. Es imperativo (no funcional) y no intenta reinventar las cosas a menos que sea absolutamente necesario.
  • Rust es moderno con soporte completo para cosas como Unicode.
  • Rust usa macros para situaciones en las que desea tener una cantidad variable de argumentos (sin sobrecarga de funciones).
  • Las macros que son "higiénicas" significa que no capturan accidentalmente identificadores del ámbito en el que se utilizan. Las macros de Rust son en realidad solo parcialmente higiénicas.

lunes, 12 de junio de 2023

Compilar y ejecutar código Rust con Cargo


Si tenemos instalados bien rust y cargo esto debería funcionar: 

$ rustc --version

rustc 1.65.0

$ cargo --version

cargo 1.65.0


Veamos como crear un binario de Rust a partir de un ejemplo:


$ cargo new exercise

     Created binary (application) `exercise` package

$ cd exercise
$ cargo run
   Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise)
    Finished dev [unoptimized + debuginfo] target(s) in 0.75s
     Running `target/debug/exercise`
Hello, world!


Reemplace el código de src/main.rs con su propio código. Por ejemplo:

fn main() {
    println!("Hola Rust!");
}

Utilizamos cargo run : 

$ cargo run
   Compiling hello_cargo v0.1.0 (/home/emanuel/Projects/rust/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 1.06s
     Running `target/debug/hello_cargo`
Hola Rust!

Usamos cargo check para revisar rápidamente el proyecto en busca de errores, usa cargo build para compilarlo sin ejecutarlo. Se encontrará el resultado en target/debug/. Usamos cargo build --release para producir una compilación de versión optimizada en target/release/.

Se puede agregar dependencias para su proyecto editando Cargo.toml. Cuando ejecutamos los comandos de cargo, automáticamente descargará y compilará las dependencias faltantes para usted.

$ cargo build --release
   Compiling hello_cargo v0.1.0 (/home/emanuel/Projects/rust/hello_cargo)
    Finished release [optimized] target(s) in 0.26s

$ cd target/release/
$ ./exercise
Hola Rust!

Y listo!!