Capítulo 1. Verdad o consecuencia
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
Y la verdad es que no sabemos nada
They Might Be Giants, "Ana Ng" (1988)
En este capítulo, te mostraré cómo organizar, ejecutar y probar un programa Rust. Utilizaré una plataforma Unix (macOS) para explicar algunas ideas básicas sobre los programas de línea de comandos.Sólo algunas de estas ideas se aplican al sistema operativo Windows, pero los programas Rust en sí funcionarán igual independientemente de la plataforma que utilices.
Aprenderás a hacer lo siguiente:
-
Compilar código Rust en un ejecutable
-
Utiliza Cargo para iniciar un nuevo proyecto
-
Utiliza la variable de entorno
$PATH
-
Incluir cajas Rust externas de crates.io
-
Interpretar el estado de salida de un programa
-
Utilizar comandos y opciones comunes del sistema
-
Escribe versiones en Rust de los programas
true
yfalse
-
Organizar, escribir y ejecutar pruebas
Empezar con "¡Hola, mundo!"
Parece que la forma universalmente aceptada de empezar a aprender un lenguaje de programación es imprimir "¡Hola, mundo!" en la pantalla. Cambia a un directorio temporal con cd /tmp
para escribir este primer programa. Sólo estamos trasteando, así queaún nonecesitamos undirectorioreal.A continuación, enciende un editor de texto y escribe el siguiente código en un archivo llamado hola.rs:
fn
main
(
)
{
println!
(
"
Hello, world!
"
)
;
}
Las funciones se definen mediante
fn
. El nombre de esta función esmain
.println!
(imprimir línea) es una macro e imprimirá texto enSTDOUT
(pronunciado salida estándar). El punto y coma indica el final de la sentencia.
Rust se iniciará automáticamente en la función main
. Los argumentos de la función aparecen dentro de los paréntesis que siguen al nombre de la función. Como no hay argumentos en main()
, la función no toma argumentos. Lo último que señalaré aquí es que println!
parece una función, pero en realidad es una macro, que en esencia es código que escribe código. Todas las demás macros que utilizo en este libro -como assert!
y vec!
-también terminan con un signo de exclamación.
Para ejecutar este programa, primero debes utilizar el compilador de Rust, rustc
, para compilar el código de forma que tu ordenador pueda ejecutarlo:
$ rustc hello.rs
En Windows, utilizarás este comando:
> rustc.exe .\hello.rs
Si todo va bien, no saldrá nada del comando anterior, pero ahora deberías tener un nuevo archivo llamado hola en macOS y Linux o hola.exe en Windows. Se trata de un archivo codificado en binario que puede ser ejecutado directamente por tu sistema operativo, por lo que es habitual llamarlo ejecutable o binario. En macOS, puedes utilizar el comando file
para ver qué tipo de archivo es:
$ file hello hello: Mach-O 64-bit executable x86_64
Deberías poder ejecutar el programa para ver un mensaje encantador y sincero:
$ ./hello Hello, world!
Consejo
En breve hablaré de la variable de entorno $PATH
, que enumera los directorios en los que buscar programas para ejecutarlos. El directorio de trabajo actual nunca se incluye en esta variable para evitar que se ejecute subrepticiamente código malicioso. Por ejemplo, un malhechor podría crear un programa llamado ls
que ejecutara rm -rf /
en un intento de borrar todo tu sistema de archivos. Si por casualidad lo ejecutaras como usuario root, te arruinaría todo el día.
En Windows, puedes ejecutarlo así:
> .\hello.exe Hello, world!
Enhorabuena si ése ha sido tu primer programa en Rust. A continuación, te mostraré cómo organizar mejor tu código.
Organizar un directorio de proyectos de óxido
En tus proyectos de Rust de , probablemente escribirás muchos archivos de código fuente y también utilizarás código de otras personas de lugares como crates.io. Lo mejor es crear un directorio para cada proyecto, con un subdirectorio src para los archivos de código fuente de Rust.En un sistema Unix, primero tendrás que eliminar el binario hello con el comando rm hello
porque ése es el nombre del directorio que vas a crear.A continuación, puedes utilizar el siguiente comando para crear la estructura del directorio:
$ mkdir -p hello/src
El comando
mkdir
creará un directorio. La opción-p
dice que hay que crear directorios padre antes de crear directorios hijo. PowerShell no requiere esta opción.
Mueve el archivo fuente hello.rs a hello/src utilizando el comando mv
:
$ mv hello.rs hello/src
Utiliza el comando cd
para cambiar a ese directorio y volver a compilar tu programa:
$ cd hello $ rustc src/hello.rs
Ahora deberías tener un ejecutable hello
en el directorio. Utilizaré el comando tree
(que puede que necesites instalar) para mostrarte el contenido de mi directorio:
$ tree . ├── hello └── src └── hello.rs
Esta es la estructura básica de un proyecto Rust sencillo.
Crear y ejecutar un proyecto con Cargo
Una forma más fácil de empezar un nuevo proyecto Rust es utilizar la herramienta Cargo. Puedes borrar tu directorio temporal hello:
$ cd .. $ rm -rf hello
Cambia al directorio padre, que se indica con dos puntos (
..
).La opción
-r
recursiva eliminará el contenido de un directorio, y la opción-f
forzar omitirá cualquier error.
Si quieres guardar el siguiente programa, cámbiate al directorio de soluciones de tus proyectos. A continuación, inicia de nuevo tu proyecto utilizando Cargo de esta forma:
$ cargo new hello Created binary (application) `hello` package
Esto debería crear un nuevo directorio hola en el que puedes cambiar. Utilizaré de nuevo tree
para mostrarte el contenido:
$ cd hello $ tree . ├── Cargo.toml └── src └── main.rs
Cargo.toml es un archivo de configuración del proyecto. La extensión .toml significa Lenguaje Mínimo y Obvio de Tom.
El directorio src es para los archivos del código fuente de Rust.
main.rs es el punto de inicio por defecto de los programas Rust.
Puedes utilizar el siguiente comando cat
(para concatenar) para ver el contenido del único archivo fuente que Cargo ha creado (en el Capítulo 3, escribirás una versión Rust de cat
):
$ cat src/main.rs fn main() { println!("Hello, world!"); }
Más bien que utilizar rustc
para compilar el programa, esta vez utiliza cargo run
para compilar el código fuente y ejecutarlo en un solo comando:
$ cargo run Compiling hello v0.1.0 (/private/tmp/hello) Finished dev [unoptimized + debuginfo] target(s) in 1.26s Running `target/debug/hello` Hello, world!
Las tres primeras líneas son información sobre lo que está haciendo Cargo.
Este es el resultado del programa.
Si quieres que Cargo no imprima mensajes de estado sobre la compilación y ejecución del código, puedes utilizar la opción -q
, o --quiet
:
$ cargo run --quiet Hello, world!
Después de ejecutar el programa utilizando Cargo, utiliza el comando ls
para listar el contenido del directorio de trabajo actual.(Escribirás una versión Rust de ls
en el Capítulo 14.) Debería haber un nuevo directorio llamado target. Por defecto, Cargo construirá un target de depuración, por lo que verás el directorio target/debug que contiene los artefactos de construcción:
$ ls Cargo.lock Cargo.toml src/ target/
Puedes utilizar el comando tree
de antes o el comando find
(escribirás una versión Rust de find
en el Capítulo 7) para ver todos los archivos que Cargo y Rust crearon.El archivo ejecutable que se ejecutó debe existir como target/debug/hello. Puedes ejecutarlo directamente:
$ ./target/debug/hello Hello, world!
En resumen, Cargo encontró el código fuente en src/main.rs, utilizó la función main
de allí para construir el archivo binario target/debug/hello, y luego lo ejecutó. Pero, ¿por qué el archivo binario se llamaba hello y no main? Para responder a eso, mira Cargo.toml:
$ cat Cargo.toml [package] name = "hello" version = "0.1.0" edition = "2021" # See more keys and their definitions at # https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies]
Éste era el nombre del proyecto que creé con Cargo, así que también será el nombre del ejecutable.
Esta es la versión del programa.
Esta es la edición de Rust que debe utilizarse para compilar el programa. Las ediciones son la forma en que la comunidad de Rust introduce cambios que no son compatibles con versiones anteriores. Utilizaré la edición 2021 para todos los programas de este libro.
Esta es una línea de comentario que incluiré sólo esta vez. Si quieres, puedes eliminar esta línea de tu archivo.
Aquí es donde enumerarás las cajas externas que utiliza tu proyecto. Este proyecto no tiene ninguna en este momento, así que esta sección está en blanco.
Nota
Las bibliotecas de Rust se llaman crates, y se espera que utilicen números de versión semánticos de la forma major.minor.patch
de modo que 1.2.4
sea versión mayor 1, versión menor 2, versión parche 4. Un cambio en la versión mayor indica un cambio de última hora en la interfaz pública de programación de aplicaciones (API) de la crate.
Escribir y ejecutar pruebas de integración
"Más que el acto de probar, el acto de diseñar pruebas es uno de los mejores preventivos de errores que se conocen. La reflexión que hay que hacer para crear una prueba útil puede descubriryeliminar errores antes de que se codifiquen; de hecho, la reflexión sobre el diseño de las pruebas puede descubriry eliminar errores en cada fase de la creación del software, desde la concepción a la especificación, pasando por el diseño, la codificación y el resto."
Boris Beizer, Técnicas de comprobación de software (Van Nostrand Reinhold)
Aunque "¡Hola, mundo!" es bastante simple, todavía hay cosas que podrían soportar pruebas. Hay dos grandes categorías de pruebas que mostraré en este libro.Las pruebasde dentroa fuera o unitarias son cuando escribes pruebas para las funciones dentro de tu programa. Presentaré las pruebas unitarias en el Capítulo 5. Las pruebas defuera a dentro o de integración son cuando escribes pruebas que ejecutan tus programas como podría hacerlo el usuario, y eso es lo que haremos para este programa. La convención en los proyectos Rust es crear un directorio de pruebas paralelo al directorio src para probar el código, y puedes utilizar el comando mkdir tests
para ello.
El objetivo es probar el programa hello
ejecutándolo en la línea de comandos como lo hará el usuario. Crea el archivo tests/cli.rs para la interfaz de línea de comandos (CLI) con el siguiente código.Ten en cuenta que esta función pretende mostrar la prueba más sencilla posible en Rust, pero aún no hace nada útil:
#[
test
]
fn
works
(
)
{
assert!
(
true
)
;
}
El atributo
#[test]
indica a Rust que ejecute esta función al realizar la prueba.La macro
assert!
afirma que una expresión booleana estrue
.
Ahora tu proyecto debería tener este aspecto:
$ tree -L 2 . ├── Cargo.lock ├── Cargo.toml ├── src │ └── main.rs ├── target │ ├── CACHEDIR.TAG │ ├── debug │ └── tmp └── tests └── cli.rs
El archivoCargo.lock registra las versiones exactas de las dependencias utilizadas para construir tu programa. No debes editar este archivo.
El directorio src es para los archivos del código fuente de Rust para construir el programa.
El directorio de destino contiene los artefactos de construcción.
El directorio tests contiene el código fuente Rust para probar el programa.
Todas las pruebas de este libro utilizarán assert!
para verificar que alguna expectativa es true
, o assert_eq!
para verificar que algo es un valor esperado. Dado que esta prueba evalúa el valor literal true
, siempre tendrá éxito. Para ver esta prueba en acción, ejecuta cargo test
Deberías ver estas líneas entre la salida:
running 1 test test works ... ok
Para observar una prueba fallida de , cambia true
por false
en el archivo tests/cli.rs:
#[
test
]
fn
works
(
)
{
assert!
(
false
)
;
}
Entre la salida, deberías ver la siguiente prueba fallida:
running 1 test test works ... FAILED
Consejo
Puedes tener tantas llamadas a assert!
y assert_eq!
en una función de prueba como quieras. Al primer fallo de una de ellas, falla toda la prueba.
Ahora, vamos a crear una prueba más útil que ejecute un comando y compruebe el resultado.El comando ls
funciona tanto en Unix como en Windows PowerShell, así que empezaremos con él. Sustituye el contenido de tests/cli.rs por el siguiente código:
use
std
::
process
::
Command
;
#[
test
]
fn
runs
(
)
{
let
mut
cmd
=
Command
::
new
(
"
ls
"
)
;
let
res
=
cmd
.
output
(
)
;
assert!
(
res
.
is_ok
(
)
)
;
}
Importa
std::process::Command
. Elstd
nos dice que esto está en la biblioteca estándar y es código de Rust tan universalmente útil que se incluye con el lenguaje.Crea un nuevo
Command
para ejecutarls
. La palabra clavelet
vinculará un valor a una variable. La palabra clavemut
hará mutable esta variable para que pueda cambiar.Ejecuta el comando y captura la salida, que será un archivo
Result
.Comprueba que el resultado es una variante de
Ok
, lo que indica que la acción se ha realizado correctamente.
Consejo
Por defecto, las variables de Rust son inmutables, lo que significa que sus valores no pueden cambiarse.
Ejecuta cargo test
y comprueba que ves una prueba superada entre todos los resultados:
running 1 test test runs ... ok
Actualiza tests/cli.rs con el siguiente código para que la función runs
ejecute hello
en lugar de ls
:
use
std
::
process
::
Command
;
#[
test
]
fn
runs
(
)
{
let
mut
cmd
=
Command
::
new
(
"
hello
"
)
;
let
res
=
cmd
.
output
(
)
;
assert!
(
res
.
is_ok
(
)
)
;
}
Ejecuta de nuevo la prueba y observa que falla porque no se encuentra el programa hello
:
running 1 test test runs ... FAILED
Recuerda que el binario existe en target/debug/hello. Si intentas ejecutar hello
en la línea de comandos, verás que no se encuentra el programa:
$ hello -bash: hello: command not found
Cuando ejecutes cualquier comando, tu sistema operativo buscará en un conjunto predefinido de directorios algo con ese nombre.1
En los sistemas de tipo Unix, puedes inspeccionar la variable de entorno PATH
de tu shell para ver esta lista de directorios, que están delimitados por dos puntos. (En Windows, es $env:Path
.) Puedo utilizar tr
(traducir caracteres) para sustituir los dos puntos (:
) por nuevas líneas (\n
) para mostrarte mi PATH
:
$ echo $PATH | tr : '\n' /opt/homebrew/bin /Users/kyclark/.cargo/bin /Users/kyclark/.local/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin
Aunque cambie al directorio de destino/depuración, hello
sigue sin encontrarse debido a las restricciones de seguridad antes mencionadas que excluyen el directorio de trabajo actual de mi PATH
:
$ cd target/debug/ $ hello -bash: hello: command not found
Debo hacer referencia explícita al directorio de trabajo actual para que el programa se ejecute:
$ ./hello Hello, world!
A continuación, necesito encontrar una forma de ejecutar binarios que sólo existan en el crate actual.
Añadir dependencias del proyecto
Actualmente, el programa hello
sólo existe en el directorio target/debug.Si lo copio en cualquiera de los directorios de mi PATH
(ten en cuenta que incluyo el directorio $HOME/.local/bin para los programas privados), puedo ejecutarlo y realizar la prueba con éxito. Pero no quiero copiar mi programa para probarlo, sino que quiero probar el programa que vive en el crate actual.Puedo utilizar el crate assert_cmd
para encontrar el programa en mi directorio crate.También añadiré el crate pretty_assertions
para utilizar una versión de la macro assert_eq!
que muestre las diferencias entre dos cadenas mejor que la versión por defecto.
Primero tengo que añadirlas como dependencias de desarrollo a Cargo.toml.Esto indica a Cargo que necesito estas cajas sólo para pruebas y evaluaciones comparativas:
[
package
]
name
=
"
hello
"
version
=
"
0.1.0
"
edition
=
"
2021
"
[
dependencies
]
[
dev-dependencies
]
assert_cmd
=
"
2.0.13
"
pretty_assertions
=
"
1.4.0
"
Entonces puedo utilizar assert_cmd
para crear un Command
que busque en los directorios binarios de Cargo.La siguiente prueba no verifica que el programa produzca la salida correcta, sólo que parece tener éxito.Actualiza tu tests/cli.rs con el siguiente código para que la función runs
utilice assert_cmd::Command
en lugar de std::process::Command
:
use
assert_cmd
::
Command
;
#[
test
]
fn
runs
(
)
{
let
mut
cmd
=
Command
::
cargo_bin
(
"
hello
"
)
.
unwrap
(
)
;
cmd
.
assert
(
)
.
success
(
)
;
}
Importa
assert_cmd::Command
.Crea un
Command
para ejecutarhello
en la caja actual. Esto devuelve unResult
, y el código llama aResult::unwrap
porque el binario debería encontrarse. Si no lo hace,unwrap
provocará un pánico y la prueba fallará, lo cual es bueno.Utiliza
Assert::success
para asegurarte de que la orden se ha ejecutado correctamente.
Nota
Tendré más que decir sobre el tipo Result
en capítulos posteriores. Por ahora, basta con saber que se trata de una forma de modelar algo que puede tener éxito o fracasar para lo que existen dos variantes posibles, Ok
y Err
, respectivamente.
Ejecuta cargo test
de nuevo y comprueba que ahora ves una prueba superada:
running 1 test test runs ... ok
Comprender los valores de salida del programa
¿Qué significa que un programa se ejecute correctamente?Los programas de línea de comandos deben informar de un estado de salida final al sistema operativo para indicar éxito o fracaso. Los estándares de la Interfaz de Sistemas Operativos Portátiles (POSIX) dictan que el código de salida estándar es 0 para indicar éxito (piensa en cero errores) y cualquier número del 1 al 255 en caso contrario.Puedo mostrarte esto utilizando el intérprete de comandos bash
y el comando true
. Aquí está la página del manual de man true
para la versión que existe en macOS:
TRUE(1) BSD General Commands Manual TRUE(1) NAME true -- Return true value. SYNOPSIS true DESCRIPTION The true utility always returns with exit code zero. SEE ALSO csh(1), sh(1), false(1) STANDARDS The true utility conforms to IEEE Std 1003.2-1992 (''POSIX.2''). BSD June 27, 1991 BSD
Como indica la documentación, este programa no hace nada excepto devolver el código de salida cero.Si ejecuto true
no produce ninguna salida, pero puedo inspeccionar la variable bash
$?
para ver el estado de salida del comando más reciente:
$ true $ echo $? 0
El comando false
es un corolario en el sentido de que siempre sale con un código de salida distinto de cero:
$ false $ echo $? 1
Se espera que todos los programas que escribas en este libro devuelvan cero cuando terminen normalmente y un valor distinto de cero cuando se produzca un error. Puedes escribir versiones de true
y false
para comprobarlo. Empieza creando un directorio src/bin utilizando mkdir src/bin
y luego crea src/bin/true.rs con el siguiente contenido:
fn
main
(
)
{
std
::
process
::
exit
(
0
)
;
}
Utiliza la función
std::process::exit
para salir del programa con el valor cero.
Tu directorio src debería tener ahora la siguiente estructura:
$ tree src/ src/ ├── bin │ └── true.rs └── main.rs
Ejecuta el programa y comprueba manualmente el valor de salida:
$ cargo run --quiet --bin true $ echo $? 0
Añade la siguiente prueba a tests/cli.rs para asegurarte de que funciona correctamente. No importa si la añades antes o después de la función runs
existente:
#[test]
fn
true_ok
()
{
let
mut
cmd
=
Command
::cargo_bin
(
"true"
).
unwrap
();
cmd
.
assert
().
success
();
}
Si ejecutas cargo test
deberías ver los resultados de las dos pruebas:
running 2 tests test true_ok ... ok test runs ... ok
Nota
Las pruebas no se ejecutan necesariamente en el mismo orden en que se declaran en el código. Esto se debe a que Rust es un lenguaje seguro para escribir código concurrente, lo que significa que el código puede ejecutarse a través de múltiples hilos. Las pruebas aprovechan esta concurrencia para ejecutar muchas pruebas en paralelo, por lo que los resultados de las pruebas pueden aparecer en un orden diferente cada vez que las ejecutas. Se trata de una característica, no de un error. Si quieres ejecutar las pruebas en orden, puedes ejecutarlas en un único subproceso mediante cargo test -- --test-threads=1
.
Los programas Rust saldrán con el valor cero por defecto. Recuerda que src/main. rs no llama explícitamente a std::process::exit
. Esto significa que el programa true
puede no hacer nada en absoluto. ¿Quieres estar seguro? Cambia src/bin/true.rs por lo siguiente:
fn
main
()
{}
Ejecuta el conjunto de pruebas y comprueba que sigue pasando. A continuación, vamos a escribir una versión del programa false
con el siguiente código fuente en src/bin/false.rs:
fn
main
(
)
{
std
::
process
::
exit
(
1
)
;
}
Comprueba manualmente que el valor de salida del programa no es cero:
$ cargo run --quiet --bin false $ echo $? 1
A continuación, añade esta prueba a tests/cli.rs para verificar que el programa informa de un fallo cuando se ejecuta:
#[
test
]
fn
false_not_ok
(
)
{
let
mut
cmd
=
Command
::
cargo_bin
(
"
false
"
)
.
unwrap
(
)
;
cmd
.
assert
(
)
.
failure
(
)
;
}
Utiliza la función
Assert::failure
para asegurarte de que el comando ha fallado.
Ejecuta cargo test
para comprobar que todos los programas funcionan como se espera:
running 3 tests test runs ... ok test true_ok ... ok test false_not_ok ... ok
Otra forma de escribir el programa false
utiliza std::process::abort
. Cambia src/bin/false.rs por lo siguiente:
fn
main
()
{
std
::process
::abort
();
}
De nuevo, ejecuta el conjunto de pruebas para asegurarte de que el programa sigue funcionando como se esperaba.
Probar la salida del programa
Aunque es bueno saber que mi programa hello
sale correctamente, me gustaría asegurarme de que realmente imprime la salida correcta en STDOUT
, que es el lugar estándar donde debe aparecer la salida y suele ser la consola.Actualiza tu función runs
en tests/cli.rs a losiguiente:
use
assert_cmd
::
Command
;
use
pretty_assertions
::
assert_eq
;
#[
test
]
fn
runs
(
)
{
let
mut
cmd
=
Command
::
cargo_bin
(
"
hello
"
)
.
unwrap
(
)
;
let
output
=
cmd
.
output
(
)
.
expect
(
"
fail
"
)
;
assert!
(
output
.
status
.
success
(
)
)
;
let
stdout
=
String
::
from_utf8
(
output
.
stdout
)
.
expect
(
"
invalid UTF-8
"
)
;
assert_eq!
(
stdout
,
"
Hello, world!
\n
"
)
;
}
Importa la macro
pretty_assertions::assert_eq
para comparar valores en lugar de la versión estándar de Rust.Llama a
Command::output
para ejecutar el comandohello
. UtilizaResult::expect
para obtener la salida del comando o muere con el mensaje "fallo".Convierte la salida del programa a UTF-8, de lo que hablaré más detenidamente en el capítulo 4.
Compara la salida del programa con un valor esperado. Ten en cuenta que esto utilizará la versión
pretty_assertions
de la macroassert_eq
.
Ejecuta las pruebas y comprueba que, efectivamente, hello
funciona correctamente. A continuación, modifica src/main.rs para añadir algunos signos de exclamación más:
fn
main
()
{
println!
(
"Hello, world!!!"
);
}
Ejecuta de nuevo las pruebas para observar una prueba fallida:
running 3 tests test true_ok ... ok test false_not_ok ... ok test runs ... FAILED failures: ---- runs stdout ---- thread runs panicked at tests/cli.rs:10:5: assertion failed: `(left == right)` Diff < left / right > : <Hello, world!!! >Hello, world!
El resultado de la prueba anterior se esfuerza por mostrarte cómo la salida esperada (la "derecha") difiere de la salida real (la "izquierda").La salida del terminal incluye incluso texto en rojo y verde y texto resaltado que no puede reproducirse aquí. Aunque se trata de un programa trivial, espero que puedas ver el valor de comprobar automáticamente todos los aspectos de los programas que escribimos.
Los valores de salida hacen que los programas sean componibles
Informar correctamente del estado de salida es una característica de los programas de línea de comandos que se comportan bien.El valor de salida es importante porque un proceso fallido utilizado junto con otro proceso debe hacer que la combinación falle. Por ejemplo, puedo utilizar el operador lógico y &&
en bash
para encadenar los dos comandos true
y ls
. Sólo si el primer proceso informa de que ha tenido éxito, se ejecutará el segundo proceso:
$ true && ls Cargo.lock Cargo.toml src/ target/ tests/
Si en su lugar ejecuto false && ls
el resultado es que el primer proceso falla y ls
nunca se ejecuta.Además, el estado de salida de todo el comando es distinto de cero:
$ false && ls $ echo $? 1
Garantizar que los programas de línea de comandos informen correctamente de los errores hace que sean compatibles con otros programas. En los entornos Unix es muy habitual combinar muchos comandos pequeños para crear programas ad hoc en la línea de comandos. Si un programa encuentra un error pero no informa de él al sistema operativo, los resultados podrían ser incorrectos. Es mucho mejor que un programa aborte para que se puedan solucionar los problemas subyacentes.
Resumen
Este capítulo te ha presentado algunas ideas clave sobre la organización de un proyecto Rust y algunas ideas básicas sobre los programas de línea de comandos. Recapitulando:
-
El compilador de Rust
rustc
compila el código fuente de Rust en un archivo ejecutable por la máquina en Windows, macOS y Linux. -
La herramienta Cargo creará un nuevo proyecto Rust, además de compilar, ejecutar y probar el código.
-
Por defecto
cargo new
crea un nuevo programa Rust que imprime "¡Hola, mundo!". -
Las herramientas de línea de comandos como
ls
,cd
,mkdir
yrm
suelen aceptar argumentos de línea de comandos como nombres de archivos o directorios, así como opciones como-f
o-p
. -
Los programas compatibles con POSIX deben salir con un valor de 0 para indicar éxito y con cualquier valor entre 1 y 255 para indicar un error.
-
Aprendiste a añadir dependencias de crates a Cargo.toml y a utilizar los crates en tu código.
-
Has creado un directorio de pruebas para organizar el código de pruebas, y has utilizado
#[test]
para marcar las funciones que deben ejecutarse como pruebas. -
Has aprendido a comprobar el estado de salida de un programa y a comprobar el texto impreso en
STDOUT
. -
Aprendiste a escribir, ejecutar y probar binarios alternativos en un proyecto Cargo creando archivos de código fuente en el directorio src/bin.
-
Escribiste tus implementaciones de los programas
true
yfalse
junto con pruebas para verificar que tienen éxito y fallan según lo esperado. Has visto que, por defecto, un programa Rust saldrá con el valor cero y que la funciónstd::process::exit
puede utilizarse para salir explícitamente con un código determinado. Además, la funciónstd::process::abort
puede utilizarse para salir con un código de error distinto de cero.
En el próximo capítulo, te mostraré cómo escribir un programa que utilice argumentos de la línea de comandos para modificar la salida.
1 Los alias de shell y las funciones también pueden ejecutarse como comandos, pero en este punto sólo estoy hablando de encontrar programas para ejecutar.
Get Línea de comandos Óxido now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.