Recibiendo datos del usuario
Clase 7 de 20 • Curso de Rust básico
Contenido del curso
Clase 7 de 20 • Curso de Rust básico
Contenido del curso
Carlos José González Juan
Hecot Pulido
Carlos José González Juan
Leandro Ariel Labiano Ramo
Hecot Pulido
Milton Mazzarri
Alan Yahir Juárez Rubio
Andersson Johan Ramirez Mosquera
Yamid Noguera
Raul Armas
Carlos Rodríguez
Camila Catalini
Rodrigo Andrés Moreno Pertúz
Cristian Fernando Anaya Perez
Hecot Pulido
Fernando Muñoz
Hecot Pulido
Andersson Johan Ramirez Mosquera
Luis Suárez
Andres Ricardo Chacon Barrueco
Abrahan Gil
Abrahan Gil
Enrique Andres Gonzalez Pelaez
Hecot Pulido
Mauricio Sebastian Gutierrez Perdomo
Luis Miguel Aranguren Ardila
Hecot Pulido
Andres Felipe Garcia Echeverria
Jerónimo Chica
Hecot Pulido
Jairo Bueno
Carlos Rodríguez
Estuardo Efraín Ramos Castro
Carlos Rodríguez
Muy buena solucion 😌
Muchas gracias Hector
Pequeño dato, Rust tiene como estandar usar snake case para declaraciones, en caso de que no la utilices te lo señalizara como un warning en tiempo de compilacion.
fn main() { // snake case work fine let var_en_snake_case: u8 = 8 ; //Camel Case, Warning in compilation time let varEnCamelCase: u8 = 8; }
Me encanta lo bien estandarizado que esta todo c:
Quería comprender por qué era necesario usar unwrap en algunas líneas del ejercicio de la clase. Así que comencé a leer sobre dicha función y resulta que la mayoría de las operaciones para entrada o salida devuelven el tipo Result<T, E>, el cual es un tipo que suele ser usado para retornar y propagar errores. Es un enum con las variantes, Ok(T), para representar el caso de éxito y contiene un valor, y Err(E), el cual representa que ocurrió un error y contiene el valor de dicho error.
enum Result<T, E> { Ok(T), Err(E), }
Una vez entendido esto, unwrap lo que hace es extraer el valor en caso de éxito, pero, dado que en la operación de entrada o salida podemos obtener un error, la documentación oficial desaconseja su uso. En vez de ello, aconsejan usar pattern matching para manejar el caso de error de manera explícita o hacer uso de unwrap_or, unwrap_or_else, unwrap_or_default.
También existen otras alternativas como expect, la cual he visto en otras soluciones acá en la sección de comentarios.
Entonces, basado en esta parte del código de la clase:
println!("age: "); let mut age : String = String::new(); std::io::stdin().read_line(&mut age).unwrap(); let age_as_integer : u8 = age.trim().parse().unwrap(); println!("Hey {name}, with {age_as_integer} years old");
Podríamos reemplazar un poco el código usando pattern matching para evitar casos de error como el siguiente:
age: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: Empty }', src/main.rs:12:50
que podrían llegar a ser un poco crípticos. En este caso, el usuario (yo), introdujo un valor vacío por edad.
println!("age: "); let mut age : String = String::new(); match std::io::stdin().read_line(&mut age) { Ok(n) if n > 1 => { let age_as_integer : u8 = age.trim().parse().expect("expected a positive number"); println!("Hey {name}, with {age_as_integer} years old"; } Ok(_) => { println!("error: age value cannot be empty") } Err(error) => println!("error: {error}") };
En este caso capturo n, el cual es el número de bytes leídos, y si dicho valor no es mayor a 1 pues muestro un error más ameno al usuario. Para este ejemplo el manejo explícito por medio de pattern matching no parece añadir
mayor ruido, incluso, si este bloque de código estuviese dentro de una función específica, después de mostrar el mensaje de error podría llamarse a si misma para darle otro intento al usuario. Sin embargo, supongo que en aplicaciones
más largas el manejo explícito de errores por medio de match puede volverse tedioso, y allí, si es más conveniente usar otros helpers como expect o los menciones previamente.
Así es, unwrap lo que hace es extraer el valor del enum Result<T, E>, (donde T es un tipo genérico, es decir, T representa cualquier tipo de dato como u8, i16, &str, String). Si el Result es Ok(T), devuelve el valor T; en caso contrario, si es Err(E), el programa entra en pánico (panic!) y finaliza la ejecución.
Por otra parte, .expect también extrae el valor, pero permite imprimir un mensaje de error personalizado antes de hacer panic!.
Por último, si queremos hacer un manejo explícito del error, especialmente si queremos evitar que nuestro código entre en pánico (i.e. panic!), podemos hacer uso de unwrap_or, unwrap_or_else, unwrap_or_default, o manejar el Result de manera más controlada con pattern matching.
Aquí muestro mi código usando unwrap, .expect y pattern matching:
use std::io::Write; fn main() { print!("Please, input your name: "); // Flush utilizado porque `print!` no lo implementa automáticamente std::io::stdout().flush().expect("Failed to flush"); let mut name: String = String::new(); std::io::stdin().read_line(&mut name).unwrap(); // Shadowing: la variable `let mut name: String` es reemplazada por `let // name: &str` // Se usa `&str` porque no es necesario mutabilidad, es más eficiente y // porque `.trim()` devuelve `&str` let name: &str = name.trim(); let age: u8 = loop { let mut age: String = String::new(); print!("Please, input your age: "); std::io::stdout().flush().expect("Failed to flush"); std::io::stdin().read_line(&mut age).unwrap(); match age.trim().parse() { // `break` funciona similar a `return`, rompe el ciclo y devuelve el // valor obtenido de la posterior expresión Ok(n) => break n, Err(_) => println!("Please input a valid positive integer"), }; }; println!("Hello, my name is {} and I'm {} years old", name, age); }
Se puede desestructurar las librerias importanto solo el componente que se va a utilizar con la palabra reservada use
use std::io; fn main() { println!( "Hello {}, you have {} years old!", &get_name_from_user(), &get_age_from_user() ); } fn get_name_from_user() -> String { println!("Please insert your name"); let mut name = String::new(); io::stdin() .read_line(&mut name) .expect("Failed to read line"); name.trim().to_string() } fn get_age_from_user() -> u8 { println!("Please insert your age"); let mut age = String::new(); io::stdin() .read_line(&mut age) .expect("Failed to read line"); age.trim().parse().unwrap() }
El tema de el &str y String por ejemplo, así como otros lenguajes, &str hace referencia al contenido de un tipo de dato nativo y el contenido de una posición de memoria, mientras que el String sería como un Objeto en POO,
También se puede importar stdin para evitar llamarlo desde std cada vez que querramos usarlo, ejemplo:
use std::io::stdin; fn main() { let mut name: String = String::new(); println!("Ingrese su nombre:"); stdin().read_line(&mut name).unwrap(); }
Que gran aporte.
Hola! fui comentando la explicacion de cada funcion, quizas les sirva
// mut --> para que pueda ser editable con las distintas ejecuciones // = String::new() --> string vacio let mut name: String = String::new(); /* --> para el ingreso de datos * std --> libreria standard de rust * io --> input and output * stdin() --> fn para el ingreso de datos * read_line(name) --> leer datos desde la consola que se van a guardar en name * unwrap() --> para el manejo de errores */ std::io::stdin().read_line(&mut name).unwrap(); /* * trim() --> para que quede mostrado en una linea en consola * to_string() --> castea a string */ name = name.trim().to_string(); print!("Enter your lastname please: "); let mut lastname: String = String::new(); std::io::stdin().read_line(&mut lastname).unwrap(); lastname = lastname.trim().to_string(); print!("Enter your age please: "); let mut age: String = String::new(); std::io::stdin().read_line(&mut age).unwrap(); /* * se puede poner cualquier cosa como edad * parse() --> convierte el string a numero borrando lo que no sea * unwrap() --> maneja errores */ let age_int : u8 = age.trim().parse().unwrap(); println!("Hi {} {}. Your age is {} years.", name, lastname, age_int);
documentacion
`Porque pese a que escribo el comando "".trim()"" en el apartado de: // Convertir esa edad a un numero No se coloca correctamente al ejecutar, se ve asi (ejemplo): Hola, bienvenido o bienvenida Cris de 100 años Me funciona escribir en el apartado de ""// Obtener la edad de la persona""
// Obtener la edad de la persona println!("Por favor introduce tu edad: "); let mut edad : String = String::new(); std::io::stdin().read_line(&mut edad).unwrap(); edad = edad.trim().to_string();
No lo complia si esta en el apartado de
// Convertir esa edad a un numero let _edad_int : u8 = edad.parse().unwrap();
Al final la ulitma parte me queda asi
// Obtener la edad de la persona println!("Por favor introduce tu edad: "); let mut edad : String = String::new(); std::io::stdin().read_line(&mut edad).unwrap(); edad = edad.trim().to_string(); // Convertir esa edad a un numero let _edad_int : u8 = edad.parse().unwrap();
¿Que tipo de error te lanza para entenderlo juntos? 👀
Podrías entrar un poco más en detalle acerca de la diferencia entre &str y String? O dejar alguna lectura recomendada? Saludos Profe! Esperando este curso con ansias desde hace semanas!!!
La diferencia es sutil y no quiero confundir.
String es dinámico, pesa más y es más difícil para el compilador usarlo... pero es tiene más funciones y cosillas interesantes.
str es inmutable, es lo contrario.
Expandiré mejor esta idea en próximos cursos.
Puedes encontrar mas sobre los strings en la documentacion del lenguaje
Pequeño aporte ya que antes de hacer el curso leí un pequeño libro de rust
https://goyox86.gitbooks.io/el-libro-de-rust/content/index.html
Rust tiene 3 formas &str => es una referencia a un literal de cadena. El literal de cadena también se conoce como un segmento de cadena. Esto se debe a que a &str se refiere a una parte de una cadena.
String => es una instancia de la estructura de String
Una distinción importante entre los dos es que** &str** se almacena en la pila, y String se asigna a la pila. Esto significa que el valor de &str no puede cambiar, y su tamaño es fijo, mientras que String puede tener un tamaño desconocido en tiempo de compilación.
El tercer tipo es: char es un USV (Valor Escalar Unicode), que se representa en unicode con valores como U+221E, el unicode para '∞'.
Saludos.
Algo del reto y un poco de búsqueda jeje
fn main() { let mut country: String = String::new(); println!("Where are you from?"); std::io::stdin().read_line(&mut country).unwrap(); match country.as_str().trim() { "chile" => println!("Hola po!"), "peru" => println!("Hola pe!"), "argentina" => println!("Hola che!"), "brazil" => println!("Oi, tudo bem?"), _ => println!("Hello world"), } }
La lista podria crecer...
Tipos de números en Rust. (básico)
Enteros con signo (Desde i8 hasta i128)
También tenemos los números sin signos, para estos números tenemos el doble de tamaño(hacia la derecha).
Un ejemplo para que se entienda mejor:
fn main(){ // el rango de un numero entero con signo abarca desde -127 hasta 127 let temp_sign: i8 = -30; // tranquilo, no va a explotar. // el rango de un numero sin signo es mayor debido a que ya no tenemos los numeros con signo. let temp_usign: u8 = 255; // aqui puede que explote si usas un signo. println!("temperatura {} {}", temp_sign, temp_usign); }
Enteros sin signo (Desde u8 hasta u128)
Espero que hayan entendido un poco sobre esto, Rust tiene muchos de datos que espero nos muestren pronto en el curso :p
Tiene muchos tipos de datos** ups
Quise de una vez usar funciones
fn main() { let nombre: String = solicitar_info("cual es tu nombre?"); let pais: String = solicitar_info("de que pais vienes?"); println!("Hola {} como esta el clima en {}?", nombre, pais); } fn solicitar_info(pregunta: &str) -> String { println!("Pregunta: {}", pregunta); let mut respuesta: String = String::new(); std::io::stdin().read_line(&mut respuesta).unwrap(); return respuesta.trim().to_string() }
¡Muy buen ejercicio!
Ohh, hace poco termine un proyecto pequeño con lo poco que sabia y lo que investige. En este necesitaba datos del usuario y estas son las funciones que termine teniendo, las dejo por si a alguien le interesa.
Use loops para comprobar si la entrada es correcta y que no panickee el codigo.
fn wait_input() { println!("\nEnter to continue"); let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); } fn get_input() ->io::Result<String>{ let mut input = String::new(); io::stdout().flush()?; io::stdin().read_line(&mut input)?; Ok(input) } fn get_bool_for_input_1_or_2(indication:&str,true_print:&str, false_print:&str) ->bool{ loop { println!("{}",indication); let mut _bool = get_input().unwrap(); // _bool = _bool.trim(); match _bool.trim() { "1" => {println!("{}",true_print) ;return true}, "2" => {println!("{}",false_print) ;return false}, _ => eprintln!("Invalid input") } } } fn get_path_input(message:&str, is_file: bool) -> String { loop{ println!("{}",message); let _path = get_input().unwrap(); let path=_path.trim_end_matches(|c| c == '\r' || c == '\n' || c == '/' || c == '\\').replace('\\', "/"); // gracias a la doc que tenia un ejemplo de closure, sino iban a ser varios trim_end_matches() println!("path: {:?}",Path::new(&path)); if is_file{ if Path::new(&path).is_file(){break path} else {println!("invalid input")} } else{ if Path::new(&path).is_dir(){break path} else {println!("invalid input")} } // if Path::new(&path).exists(){break path} // Habia tenido que poner eso porque los is_... no funcionaban, saber porque, pero en 23-10-2025 si } }
las variables tienen que declararse de una manera especifica snake_case, CamelCase? como lo pide el lenguaje?
Puedes declararlas como quieras, pero lo mejor es seguir las convenciones y usar snake_case
Qué extensión usa para el autocompletado?
¿Cómo sé cuántos bits pesa una variable? A mi me funcionó con i8, ¿Por qué hacerlo con i16?
Pusieron antes esta imagen: Lo importante es saber hasta que número puede recibir tu función, si intentas ponerle un 128 a un i8, va a explotar, con i16 el número es bastante mayor.
Mi Respuesta:
fn main() { let mut nombre: String = String::new(); let mut pais: String = String::new(); println!("Por favor introduce tu nombre:"); std::io::stdin().read_line(&mut nombre).unwrap(); nombre = nombre.trim().to_string(); println!("De que pais eres:"); std::io::stdin().read_line(&mut pais).unwrap(); pais = pais.trim().to_string(); println!("Mucho gusto {}, es un bonito pais {}", nombre, pais); }
Que grande tu aporte.
Esta seria mi respuesta:
fn main() { let nombre = read_from_user("Favor de introducir nombre: "); let ciudad = read_from_user("Favor de ingresar su ciudad: "); println!("Hola, bienvenido {}, de la ciudad de {}", nombre, ciudad); } fn read_from_user(message: &str) -> String { println!("{}", message); let mut result = String::new(); std::io::stdin() .read_line(&mut result) .unwrap(); return result.trim().to_string(); }
Muchas gracias, está buenísimo.