101 / Entrada, salida y datos

Errores de archivo: dos niveles

Nyx maneja los fallos de E/S en dos niveles. El primero devuelve Result<T, Error> y lo propaga con ?, así que quien llama decide qué hacer con el fallo; el segundo llama a unwrap() y muere en el acto, que es la opción honesta cuando no hay un fallback razonable. Esta receta usa try_read_file y try_write_file de std/fs junto con std/error.

101-file-errors-two-tier.nxFuente →
// Errores tipados de E/S: Result<T, Error> cuando el caller reacciona, panic cuando morir es correcto

import "std/fs"
import "std/error"

// Nivel 1 (Result): el caller de cargar_config puede reaccionar distinto
// según el fallo, así que esta función NO decide por él — propaga el
// Error con `?` sin necesitar saber por qué try_read_file falló.
fn cargar_config(path: String) -> Result<String, Error> {
    let contenido: String = try_read_file(path)?
    return Result.Ok(contenido)
}

fn main() -> int {
    let path: String = "/tmp/nyx_example_101_config.txt"

    // Nivel 2 (panic): sembrar el archivo de ejemplo en /tmp. Si esto
    // falla, /tmp no es escribible y no hay fallback razonable — morir
    // acá con unwrap() es más honesto que seguir con un estado a medias.
    // Anotación explícita necesaria: un `let` sin tipo pierde el genérico
    // Result<T,E> (queda i8* opaco) y .unwrap() no dispatchea.
    let w: Result<int, Error> = try_write_file(path, "puerto=8080\nmodo=dev\n")
    w.unwrap()

    // Nivel 1: match exhaustivo, la config existe.
    match cargar_config(path) {
        Result.Ok(cfg) => { print(cfg) }
        Result.Err(e) => { print("no se pudo cargar config: " + error_to_string(e)) }
    }

    // Mismo Result, ahora el archivo no existe: el caller distingue el
    // tipo de fallo por e.kind sin parsear un string de mensaje.
    match cargar_config("/tmp/nyx_example_101_no_existe.txt") {
        Result.Ok(cfg) => { print(cfg) }
        Result.Err(e) => { print("kind: " + e.kind) }
    }

    return 0
}
Salidastdout
puerto=8080
modo=dev

kind: not_found

Cómo funciona

cargar_config es el primer nivel: try_read_file(path)? entrega el contenido del archivo o retorna temprano con el Error intacto. La función nunca necesita saber por qué falló la lectura — ? propaga el error tipado y Result.Ok(contenido) envuelve el caso de éxito.

Sembrar el archivo de ejemplo en /tmp es el segundo nivel. Si esa escritura falla, el directorio no es escribible y no hay un fallback sensato, así que w.unwrap() aborta. La anotación de let w: Result<int, Error> es obligatoria: un let sin tipo pierde los parámetros genéricos y .unwrap() deja de despachar.

Las dos llamadas a cargar_config se resuelven con match exhaustivo. La segunda pide un archivo que no existe, y la rama Result.Err lee e.kind — un campo del valor de error, no un mensaje que haya que parsear — y por eso la última línea de la salida es not_found.