jueves, 26 de diciembre de 2019

Empezando con Rust, parte 4

Seguimos con Rust...

Ahora vamos a modificar la función main de este modo:

use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}

Este código contiene mucha información, así que repasemos línea por línea. Para obtener la entrada del usuario y luego imprimir el resultado como salida, necesitamos la biblioteca io (entrada / salida) . La biblioteca io proviene de la biblioteca estándar (que se conoce como std):

use std::io;

La función principal es el punto de entrada al programa:

fn main() {

La sintaxis fn declara una nueva función, los paréntesis, (), indican que no hay parámetros, y el corchete, {, inicia el cuerpo de la función.

println! es una macro que imprime una cadena en la pantalla:

println!("Guess the number!");

println!("Please input your guess.");

A continuación, crearemos un lugar para almacenar la entrada del usuario, así:

let mut guess = String::new();

Tenga en cuenta que esta es una declaración let, que se utiliza para crear una variable. Aquí hay otro ejemplo:

let foo = bar;

Esta línea crea una nueva variable llamada foo y la vincula al valor de la variable de bar. En Rust, las variables son inmutables por defecto. El siguiente ejemplo muestra cómo usar mut antes del nombre de la variable para hacer que una variable sea mutable:

let foo = 5; // immutable
let mut bar = 5; // mutable

Volvamos al programa de juego de adivinanzas. Ahora sabe que let mut guess introducirá una variable mutable llamada guess. En el otro lado del signo igual (=) está el valor al que está vinculado la conjetura, que es el resultado de llamar a String :: new, una función que devuelve una nueva instancia de una cadena. String es un tipo de cadena proporcionado por la biblioteca estándar que es un bit de texto codificado en UTF-8 que puede crecer.

La sintaxis :: indica que new es una función asociada del tipo String. Una función asociada se implementa en un tipo, en este caso String, en lugar de en una instancia particular de un String. Lo podríamos pensar como un método estático.

Esta nueva función crea una nueva cadena vacía. 

Para resumir, let mut guess = String :: new (); ha creado una variable mutable que actualmente está vinculada a una nueva instancia vacía de una Cadena. 

Recuerde que incluimos la funcionalidad de entrada / salida de la biblioteca estándar con use std :: io; en la primera línea del programa. Ahora llamaremos a la función stdin desde el módulo io:

io::stdin().read_line(&mut guess)
    .expect("Failed to read line");

La función stdin devuelve una instancia de std :: io :: Stdin, que es un tipo que representa un identificador de la entrada estándar para su terminal.

La siguiente parte del código, .read_line (& mut guess), llama al método read_line en el identificador de entrada estándar para obtener información del usuario. También estamos pasando un argumento a read_line: & mut guess.

El trabajo de read_line es tomar lo que el usuario escriba en la entrada estándar y colocarlo en una cadena, por lo que toma esa cadena como argumento. El argumento de cadena debe ser mutable para que el método pueda cambiar el contenido de la cadena agregando la entrada del usuario.

El & indica que este argumento es una referencia, lo que le brinda una manera de permitir que múltiples partes de su código accedan a un dato sin necesidad de copiar esos datos en la memoria varias veces. Las referencias son una característica compleja, y una de las principales ventajas de Rust es lo seguro y fácil que es usar referencias. No necesita conocer muchos de esos detalles para finalizar este programa. Por ahora, todo lo que necesita saber es que, como las variables, las referencias son inmutables por defecto. Por lo tanto, necesita escribir & mut guess en lugar de & guess para hacerlo mutable.

No hemos terminado con esta línea de código. Aunque lo que hemos discutido hasta ahora es una sola línea de texto, es solo la primera parte de la única línea lógica de código. La segunda parte es este método:

.expect("Failed to read line");

Cuando llama a un método con la sintaxis .foo(), a menudo es aconsejable introducir una nueva línea y otros espacios en blanco para ayudar a dividir las líneas largas. Podríamos haber escrito este código como:

io::stdin().read_line(&mut guess).expect("Failed to read line");

Sin embargo, una línea larga es difícil de leer, por lo que es mejor dividirla: dos líneas para dos llamadas a métodos.

read_line coloca lo que el usuario escribe en la cadena que lo estamos pasando, pero también devuelve un valor, en este caso, un io :: Result. Rust tiene varios tipos llamados Result en su biblioteca estándar: un Result genérico y versiones específicas para submódulos, como io :: Result.

Los tipos de resultados son enumeraciones, a menudo denominadas enums. Una enumeración es un tipo que puede tener un conjunto fijo de valores, y esos valores se denominan variantes de la enumeración.

Para Result, las variantes son Ok o Err. La variante Ok indica que la operación fue exitosa, y dentro de Ok está el valor generado con éxito. La variante Err significa que la operación falló, y Err contiene información sobre cómo o por qué falló la operación.

El propósito de estos tipos de resultados es codificar la información de manejo de errores. Los valores del tipo Resultado, como los valores de cualquier tipo, tienen métodos definidos en ellos. Una instancia de io :: Result tiene un método de espera al que puede llamar. Si esta instancia de io :: Result es un valor de Err, esperar hará que el programa se bloquee y muestre el mensaje que pasó como un argumento para esperar. Si el método read_line devuelve un Err, probablemente sea el resultado de un error proveniente del sistema operativo subyacente. Si esta instancia de io :: Result es un valor Ok, esperar tomará el valor de retorno que Ok tiene y le devolverá ese valor para que pueda usarlo. En este caso, ese valor es el número de bytes en lo que el usuario ingresó en la entrada estándar.

Si no llama a wait, el programa se compilará, pero recibirá una advertencia:

$ cargo build
   Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
warning: unused `std::result::Result` which must be used
  --> src/main.rs:10:5
   |
10 |     io::stdin().read_line(&mut guess);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: #[warn(unused_must_use)] on by default

Rust le advierte que no ha utilizado el valor Resultado devuelto por read_line, lo que indica que el programa no ha manejado un posible error.

La forma correcta de suprimir la advertencia es escribir realmente el manejo de errores, pero debido a que solo desea bloquear este programa cuando se produce un problema, puede usar expect.

Además de los corchetes de cierre, solo hay una línea más para discutir en el código agregado hasta ahora, que es el siguiente:

println!("You guessed: {}", guess);

Esta línea imprime la cadena en la que guardamos la entrada del usuario. El conjunto de llaves, {}, es un marcador de posición: piense en {} como pequeñas pinzas de cangrejo que mantienen un valor en su lugar. Puede imprimir más de un valor usando llaves: el primer conjunto de llaves contiene el primer valor que aparece después de la cadena de formato, el segundo conjunto contiene el segundo valor, y así sucesivamente. Impresión de múltiples valores en una llamada a println! se vería así:

let x = 5;
let y = 10;

println!("x = {} and y = {}", x, y);

Este código imprimiría x = 5 e y = 10.

Y listo!! puf escribi mucho...


No hay comentarios.:

Publicar un comentario