traduccion ps4 lenguaje language descargar rust

rust - ps4 - ¿Por qué intentarlo() y? no se compila cuando se usa en una función que no devuelve Opción o Resultado?



rust traduccion (4)

¿Por qué este código no se compila?

use std::{fs, path::Path}; fn main() { let dir = Path::new("../FileSystem"); if !dir.is_dir() { println!("Is not a directory"); return; } for item in try!(fs::read_dir(dir)) { let file = match item { Err(e) => { println!("Error: {}", e); return; } Ok(f) => f, }; println!(""); } println!("Done"); }

Este es el error que obtengo

error[E0308]: mismatched types --> src/main.rs:11:17 | 11 | for item in try!(fs::read_dir(dir)) { | ^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result` | = note: expected type `()` found type `std::result::Result<_, _>` = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

También probé el operador de signo de interrogación:

for item in fs::read_dir(dir)? {

Que tuvo un error diferente:

error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> src/main.rs:11:17 | 11 | for item in fs::read_dir(dir)? { | ^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error`

Las versiones anteriores de Rust tenían un error similar sobre std::ops::Carrier

¿Debo evitar try!() Y ? ? ¿Cuál es la mejor manera de manejar los errores? Principalmente lo hago así:

match error_prone { Err(e) => { println!("Error: {}", e); return; }, Ok(f) => f, };

Pero si tengo que usar eso en un bucle for , es un completo desastre

for i in match error_prone { // match code } { // loop code }


A partir de Rust 1.26, Rust admite un valor de retorno de main () y, por lo tanto, admite el uso del operador de verificación de errores ? (o, de forma equivalente, la macro try!() ) en main() cuando main() está definido para devolver un Result :

extern crate failure; use failure::Error; use std::fs::File; type Result<T> = std::result::Result<T, Error>; fn main() -> Result<()> { let mut _file = File::open("foo.txt")?; // does not exist; returns error println!("the file is open!"); Ok(()) }

Lo anterior compila y devuelve un error de archivo no encontrado (asumiendo que foo.txt no existe en la ruta local).

Ejemplo de patio de óxido


El RFC ques_in_main se fusionó recientemente. Una vez que se haya completed , la sintaxis de la pregunta se compilará perfectamente y funcionará según lo previsto, siempre que las llamadas a try!() Se reemplacen con ? operador.


La respuesta de Veedrac también me ayudó, aunque la pregunta del OP es ligeramente diferente. Mientras leía la documentación de Rust, vi este fragmento:

use std::fs::File; use std::io::prelude::*; let mut file = File::open("foo.txt")?; let mut contents = String::new(); file.read_to_string(&mut contents)?; assert_eq!(contents, "Hello, world!");

Aunque en el Rust Book señalan la centralidad de la función principal, si ejecuta esto dentro de ella, obtendrá un error similar. Si envuelve el código dentro de una función que maneja los errores, el fragmento mencionado anteriormente funciona:

use std::error::Error; use std::io::prelude::*; use std::fs::File; fn print_file_content() -> Result<String, Box<Error>> { let mut f = File::open("foo.txt")?; let mut contents = String::new(); f.read_to_string(&mut contents)?; println!("The content: {:?}", contents); Ok("Done".into()) } fn main() { match print_file_content() { Ok(s) => println!("{}", s), Err(e) => println!("Error: {}", e.to_string()), } }

PD: estoy aprendiendo Rust, por lo que estos fragmentos no pretenden ser una buena codificación de Rust :)


try! es una macro que devuelve Err s automáticamente; ? es una sintaxis que hace casi lo mismo, pero funciona con cualquier tipo que implemente el rasgo Try .

A partir de Rust 1.22.0 , Option implementa Try , por lo que se puede usar con ? . Antes de eso ? solo se puede usar en funciones que devuelven un Result . try! continúa trabajando solo con Result s.

A partir de Rust 1.26.0 , main puede devolver un valor que implementa la Termination . Antes de eso, no devuelve ningún valor.

A partir de Rust 1.26.0

Su código original funciona si marca main como que devuelve un Result y luego devuelve Ok(()) en todos los casos de "éxito":

use std::{fs, io, path::Path}; fn main() -> Result<(), io::Error> { let dir = Path::new("../FileSystem"); if !dir.is_dir() { println!("Is not a directory"); return Ok(()); } for item in fs::read_dir(dir)? { let file = match item { Err(e) => { println!("Error: {}", e); return Ok(()); } Ok(f) => f, }; println!(""); } println!("Done"); Ok(()) }

Antes de que

¿Así es como podría transformar su código para usarlo ? :

use std::{error::Error, fs, path::Path}; fn print_dir_contents() -> Result<String, Box<Error>> { let dir = Path::new("../FileSystem"); if !dir.is_dir() { return Err(Box::from("Is not a directory!")); } for entry in fs::read_dir(dir)? { let path = entry?.path(); let file_name = path.file_name().unwrap(); println!("{}", file_name.to_string_lossy()); } Ok("Done".into()) } fn main() { match print_dir_contents() { Ok(s) => println!("{}", s), Err(e) => println!("Error: {}", e.to_string()), } }

Aquí hay una gran cantidad de manejo de errores que no puede esperar, ¡otros idiomas no suelen requerirlo! Pero existen en otros idiomas: Rust solo te hace saberlo. Aquí están los errores:

entry?

Los errores de E / S pueden ocurrir durante la iteración.

path.file_name().unwrap()

No todas las rutas tienen nombres de archivo. Podemos unwrap esto porque read_dir no nos dará una ruta sin un nombre de archivo.

file_name.to_string_lossy()

También puede to_str y lanzar un error, pero es mejor hacerlo. Este error existe porque no todos los nombres de archivo son válidos Unicode.

try! y ? arroje errores en el valor de retorno, convirtiéndolos en Box::Error . En realidad, es más razonable devolver un error amalgamado de todas las cosas que pueden salir mal. Afortunadamente io::Error es el tipo correcto:

use std::io; // ... fn print_dir_contents() -> Result<String, io::Error> { // ... if !dir.is_dir() { return Err(io::Error::new(io::ErrorKind::Other, "Is not a directory!")); } // ... }

Francamente, sin embargo, esta comprobación ya está en fs::read_dir , por lo que en realidad solo puede eliminar el if !dis.is_dir completo:

use std::{fs, io, path::Path}; fn print_dir_contents() -> Result<String, io::Error> { let dir = Path::new("../FileSystem"); for entry in fs::read_dir(dir)? { let path = entry?.path(); let file_name = path.file_name().unwrap(); println!("{}", file_name.to_string_lossy()); } Ok("Done".into()) } fn main() { match print_dir_contents() { Ok(s) => println!("{}", s), Err(e) => println!("Error: {}", e.to_string()), } }