Lenguaje de programación Rust - Carol; Nichols - E-Book

Lenguaje de programación Rust E-Book

Carol; Nichols

0,0
29,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.
Mehr erfahren.
Beschreibung

Descubra el mundo de Rust, el revolucionario lenguaje de programación de sistemas de código abierto que combina eficiencia con ergonomía. Le permitirá mejorar la productividad y evitar las molestias asociadas con los lenguajes de bajo nivel. Lenguaje de programación Rust es su guía definitiva para navegar por las características y capacidades únicas de Rust 2021. Escrito por Klabnik y Nichols, antiguos miembros del Rust Core Team, este libro le llevará desde los conceptos más básicos hasta las técnicas avanzada y le permitirá escribir software más rápido y confiable. "Aprenderá las innovadoras características de Rust, como la propiedad, el préstamo, los tiempos de vida, los genéricos, los traits y los objetos trait para comunicar las restricciones de su programa al compilador. "Conocerá los punteros inteligentes y multihilo, y cómo la propiedad interactúa con ellos para permitir una concurrencia segura. "Asimilará cómo utilizar Cargo, el gestor de paquetes integrado en Rust, para compilar, documentar el código y gestionar las dependencias. "Interiorizará las mejores maneras para probar, gestionar errores, refactorizar y aprovechar la concordancia expresiva de patrones. Además de los innumerables ejemplos de código, encontrará tres capítulos dedicados a la elaboración de proyectos completos: un juego numérico de adivinanzas, la implementación en Rust de una herramienta de línea de comandos y un servidor multihilo. Este libro es esencial para todo desarrollador, tanto si está buscando iniciar su viaje en Rust como si busca perfeccionar sus habilidades. ¡Embárquese en este viaje y domine Rust! SOBRE LOS AUTORES Steve Klabnik fue jefe del equipo de documentación de Rust y uno de sus principales desarrolladores. Klabnik es un conferenciante habitual y un prolífico colaborador de código abierto. Carol Nichols es miembro del equipo de Rust Crates.io y antigua miembro del Rust Core Team. Nichols es cofundadora de Integer 32, la primera consultoría de software del mundo centrada en Rust, y también ha organizado la Rust Belt Rust Conference.

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 832

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Copyright © 2023 by the Rust Foundation and the Rust Project Developers. Title of Englishlanguage original: The Rust Programming Language, 2nd Edition, ISBN 9781718503106, published by No Starch Press Inc. 245 8th Street, San Francisco, California United States 94103. The Spanish-language 2nd edition Copyright © 2024 by Marcombo, S.L. under license by No Starch Press Inc. All rights reserved.

Segunda edición original publicada en inglés por No Starch Press Inc. con el título The Rust Programming Language, ISBN 9781718503106 © Steve Klabnik y Carol Nichols, 2023.

Título de la edición en español:Lenguaje de programación Rust

Segunda edición en español, 2024

© 2024 MARCOMBO, S.L.www.marcombo.com

Ilustración de portada: Karen Rustad Tölva

Diseño del interior: Octopod Studios

Revisor técnico: JT

Traducción: Francisco Martínez Carreño

Corrección: Anna Alberola Banasco

Directora de producción: M.a Rosa Castillo

Cualquier forma de reproducción, distribución, comunicación pública o transformación de esta obra solo puede ser realizada con la autorización de sus titulares, salvo excepción prevista por la ley. La presente publicación contiene la opinión del autor y tiene el objetivo de informar de forma precisa y concisa. La elaboración del contenido, aunque se ha trabajado de forma escrupulosa, no puede comportar una responsabilidad específica para el autor ni el editor de los posibles errores o imprecisiones que pudiera contener la presente obra.

ISBN del libro en papel: 978-84-267-3751-9

ISBN del libro electrónico: 978-84-267-3838-7

Producción del ePub: booqlab

 

 

 

Sobre el autor

Steve Klabnik dirigió el equipo de documentación de Rust y fue uno de los principales desarrolladores de Rust. Conferenciante habitual y prolífico colaborador de código abierto, anteriormente trabajó en proyectos como Ruby y Ruby on Rails.

Carol Nichols es miembro del equipo de Rust Crates.io y exmiembro del equipo central de Rust. Es cofundadora de Integer 32, LLC, la primera consultoría de software del mundo centrada en Rust. Nichols también ha organizado la Rust Belt Rust Conference.

Sobre el revisor técnico

JT es miembro del equipo principal de Rust y cocreador del formato de mensajes de error de Rust, Rust Language Server (RLS) y Nushell. Empezó a usar Rust en 2011 y en 2016 se unió a Mozilla para trabajar en Rust a tiempo completo, ayudando a dar forma a su realización para su uso generalizado. En la actualidad, es formador autónomo de Rust y defensor de la programación segura de sistemas.

CONTENIDO RESUMIDO

Prólogo

Prefacio

Agradecimientos

Introducción

Capítulo 1. Empezamos

Capítulo 2. Programación de un juego de adivinanzas

Capítulo 3. Conceptos de programación habituales

Capítulo 4. Comprensión de la propiedad

Capítulo 5. Uso de structs para estructurar datos relacionados

Capítulo 6. Enums y coincidencia de patrones

Capítulo 7. Gestión de proyectos en expansión con paquetes, crates y módulos

Capítulo 8. Colecciones típicas

Capítulo 9. Gestión de errores

Capítulo 10. Tipos genéricos, traits y lifetimes

Capítulo 11. Escritura de pruebas automatizadas

Capítulo 12. Proyecto de E/S: construcción de un programa de línea de comandos

Capítulo 13. Características de los lenguajes funcionales: iteradores y closures

Capítulo 14. Más sobre Cargo y Crates.io

Capítulo 15. Punteros inteligentes

Capítulo 16. Concurrencia sin preocupación

Capítulo 17. Características de la programación orientada a objetos

Capítulo 18. Patrones y coincidencias

Capítulo 19. Características avanzadas

Capítulo 20. Proyecto final: creación de un servidor web multihilo

Apéndice A. Palabras clave

Apéndice B. Operadores y símbolos

Apéndice C. Traits derivables

Apéndice D. Herramientas útiles de desarrollo

Apéndice E. Ediciones

CONTENIDO DETALLADO

PRÓLOGO

PREFACIO

AGRADECIMIENTOS

INTRODUCCIÓN

A quién le interesa Rush

Equipos de desarrolladores

Estudiantes

Empresas

Desarrolladores de código abierto

Personas que valoran la rapidez y la estabilidad

A quién va dirigido el libro

Cómo utilizar el libro

Recursos y cómo contribuir al libro

1. EMPEZAMOS

Instalación

Instalación de rustup en Linux o macOS

Instalación de rustup en Windows

Solución de problemas

Actualización y desinstalación

Documentación local

Hello, World!

Creación de un directorio de proyectos

Escritura y ejecución de un programa en Rust

Anatomía de un programa en Rust

Compilación y ejecución son pasos separados

¡Hola, Cargo!

Creación de un proyecto con Cargo

Construcción y ejecución de un proyecto con Cargo

Construcción para la versión de lanzamiento (Release)

Cargo como convención

Resumen

2. PROGRAMACIÓN DE UN JUEGO DE ADIVINANZAS

Configuración de un nuevo proyecto

Procesamiento de una propuesta

Almacenamiento de valores con variables

Recepción de datos introducidos por el usuario

Gestión de posibles fallos con Result

Impresión de valores con println! Marcadores

Prueba de la primera parte

Generación de un número secreto

Uso de un crate para conseguir mayor funcionalidad

Generación de un número aleatorio

Comparación del número propuesto con el número secreto

Admisión de varias propuestas utilizando un bucle

Detención del programa después de hacer una propuesta acertada

Gestión de entradas no válidas

Resumen

3. CONCEPTOS DE PROGRAMACIÓN HABITUALES

Variables y mutabilidad

Constantes

Enmascaramiento

Tipos de datos

Tipos de escalares

Tipos compuestos

Funciones

Parámetros

Sentencias y expresiones

Funciones con valores de retorno

Comentarios

Control de flujo

Expresiones if

Repetición mediante bucles

Resumen

4. COMPRENSIÓN DE LA PROPIEDAD

¿Qué es la propiedad?

Reglas de la propiedad

Ámbito de las variables

El tipo String

Memoria y asignación

Propiedad y funciones

Valores de retorno y ámbito

Referencias y préstamos

Referencias mutables

Referencias colgantes

Reglas de referencias

El tipo rebanada (slice)

String slices (rebanadas de cadena)

Otras rebanadas

Resumen

5. USO DE STRUCTS PARA ESTRUCTURAR DATOS RELACIONADOS

Definición e instanciación de structs

Uso de la forma abreviada de inicialización de campos

Creación de instancias a partir de otras instancias con la sintaxis de actualización de structs

Uso de structs de tupla que no tienen nombres asociados a sus campos para crear diferentes tipos

Structs unitarias sin campos

Programa de ejemplo que utiliza structs

Refactorización con tuplas

Refactorización con structs: aclaración del significado

Mejora de la funcionalidad con traits derivados

Sintaxis de métodos

Definiciones de métodos

Métodos con más parámetros

Funciones asociadas

Varios bloques impl

Resumen

6. ENUMS Y COINCIDENCIA DE PATRONES

Definición de enum

Valores enum

Enum Option y sus ventajas sobre los valores nulos

Construcción match de control de flujo

Patrones que vinculan valores

Comparación con Option<T>

Las matches son exhaustivas

Patrones Catch-All y _ Placeholder

Control de flujo conciso con if let

Resumen

7. GESTIÓN DE PROYECTOS EN EXPANSIÓN CON PAQUETES, CRATES Y MÓDULOS

Paquetes y crates

Definición de módulos para controlar el ámbito y la privacidad

Rutas para hacer referencia a un elemento en el árbol de módulos

Exposición de rutas con la palabra clave pub

Comienzo de rutas relativas con super

Cómo hacer públicas las structs y enums

Introducción de rutas en el ámbito con la palabra clave use

Creación de rutas de use idiomáticas

Provisión de nuevos nombres con la palabra clave as

Reexportación de nombres con pub use

Uso de paquetes externos

Uso de rutas anidadas para limpiar extensas listas de use

El operador glob

Separación de módulos en diferentes archivos

Resumen

8. COLECCIONES TÍPICAS

Almacenamiento de listas de valores con vectores

Creación de un nuevo vector

Actualización de vectores

Lectura de los elementos de un vector

Iteración sobre los valores de un vector

Uso de enum para almacenar varios tipos

La eliminación de un vector elimina sus elementos

Almacenamiento de texto codificado en UTF-8 con strings

¿Qué es String?

Creación de una nueva String

Actualización de Strings

Indexación de Strings

Slicing strings (Rebanadas de cadenas)

Métodos de iteración sobre cadenas

Las cadenas no son tan simples

Almacenamiento de claves con valores asociados en mapas hash

Creación de un nuevo mapa hash

Acceso a los valores de mapas hash

Mapas hash y propiedad

Actualización de mapas hash

Funciones hashing

Resumen

9. GESTIÓN DE ERRORES

Errores irreparables con panic!

Errores reparables con Result

Coincidencia de diferentes errores

Propagación de errores

Entrar en panic! o no entrar en panic!

Ejemplos, código de prototipos y pruebas

Casos en los que tenemos más información que el compilador

Directrices para la gestión de errores

Creación de tipos personalizados para la validación

Resumen

10. TIPOS GENÉRICOS, TRAITS Y LIFETIMES

Eliminación de la duplicación de código mediante su extracción a una función

Tipos de datos genéricos

En las definiciones de funciones

En las definiciones de structs

En las definiciones de enums

En las definiciones de métodos

Rendimiento del código cuando se utilizan genéricos

Traits: definición de comportamiento compartido

Definición de trait

Implementación de un trait en un tipo

Implementaciones por defecto

Traits como parámetros

Devolución de tipos que implementan traits

Uso de las restricciones de trait para implementar métodos de forma condicional

Validación de referencias con lifetimes

Cómo evitar referencias colgantes con lifetimes

Verificador de préstamos

Lifetimes genéricos en funciones

Sintaxis de las anotaciones de lifetimes

Anotaciones de lifetimes en las firmas de las funciones

Pensar en términos de lifetimes

Anotaciones de lifetimes en las definiciones de structs

Elisión de lifetime

Anotaciones de lifetimes en las definiciones de métodos

Lifetime estático

Parámetros de tipo genérico, restricciones de traits y lifetimes juntos

Resumen

11. ESCRITURA DE PRUEBAS AUTOMATIZADAS

Cómo escribir pruebas

Anatomía de las funciones de prueba

Verificación de resultados con la macro assert!

Pruebas de igualdad con las macros assert_eq! y assert_ne!

Adición de mensajes personalizados de error

Comprobación de panics con should_panic

Uso de Result<T, E> en las pruebas

Control de la ejecución de pruebas

Ejecución de pruebas en paralelo o de forma consecutiva

Presentación de la salida de una función

Ejecución de un subconjunto de pruebas por su nombre

Omisión de algunas pruebas a menos que se soliciten expresamente

Organización de las pruebas

Pruebas unitarias

Pruebas de integración

Resumen

12. PROYECTO DE E/S: CONSTRUCCIÓN DE UN PROGRAMA DE LÍNEA DE COMANDOS

Aceptación de argumentos de la línea de comandos

Lectura de valores de los argumentos

Almacenamiento de los valores de los argumentos en variables

Lectura de archivos

Refactorización para mejorar la modularidad y la gestión de errores

Separación de responsabilidades en proyectos binarios

Corrección de la gestión de errores

Extracción de la lógica de main

Separación de código en el crate de biblioteca

Desarrollo de la funcionalidad de la biblioteca con el desarrollo dirigido por pruebas

Escritura de pruebas que fallan

Escritura de código para que la prueba pase

Trabajo con variables de entorno

Escritura de una prueba fallida para la función de búsqueda insensible a mayúsculas y minúsculas

Implementacion de la función search_case_insensitive

Escritura de mensajes de error en la salida de error estándar en lugar de en la salida estándar

Comprobación de dónde están escritos los errores

Impresión de errores en la salida de error estándar

Resumen

13. CARACTERÍSTICAS DE LOS LENGUAJES FUNCIONALES: ITERADORES Y CLOSURES

Closures: funciones anónimas que capturan su entorno

Capturas del entorno con closures

Inferencia y anotación de tipos para closures

Captura de referencias o transferencia de la propiedad

Movimiento de valores capturados afuera de los closures y los traits Fn

Procesamiento de series de elementos con iteradores

El trait iterator y el método next

Métodos que consumen al iterador

Métodos que generan otros iteradores

Uso de closures que capturan su entorno

Cómo mejorar nuestro proyecto de E/S

Eliminación de clones usando iteradores

Código más claro con adaptadores de iteradores

Cómo elegir entre bucles e iteradores

Comparación del rendimiento: bucles frente a iteradores

Resumen

14. MÁS SOBRE CARGO Y CRATES.IO

Personalización de compilaciones con perfiles de lanzamiento

Publicación de un crate en Crates.io

Cómo hacer comentarios útiles en la documentación

Exportación de una API pública adecuada con pub use

Configuración de una cuenta en Crates.io

Adición de metadatos a un nuevo crate

Publicación en Crates.io

Publicación de una nueva versión de un crate existente

Versiones obsoletas de Crates.io con cargo yank

Workspaces (espacios de trabajo) de Cargo

Creación de workspaces

Creación de un segundo paquete en workspace

Instalación de binarios con cargo install

Ampliación de cargo con comandos personalizados

Resumen

15. PUNTEROS INTELIGENTES

Uso de Box<T> para apuntar a los datos en heap

Uso de Box<T> para almacenar datos en heap

Habilitación de tipos recursivos con boxes

Tratamiento de los punteros inteligentes como referencias regulares con Deref

Seguimiento del puntero hasta el valor

Uso de Box<T> como una referencia

Definición de nuestro propio puntero inteligente

Implementación del trait Deref

Coerciones deref implícitas con funciones y metodos

Cómo interactúa la coerción deref con la mutabilidad

Ejecución de código durante la limpieza con el trait Drop

Rc<T>, el puntero inteligente con recuento de referencias

Uso de Rc<T> para compartir datos

La clonación de Rc<T> aumenta el recuento de referencias

RefCell<T> y el patrón de mutabilidad interna

Imposición de las reglas de préstamo en tiempo de ejecución con RefCell<T>

Mutabilidad interna: un préstmao mutable a un valor inmutable

Cómo permitir múltiples propietarios de datos mutables con Rc<T> y RefCell<T>

Los ciclos de referencia pueden provocar fuga de memoria

Creación de ciclos de referencia

Prevención de ciclos de referencia mediante Weak<T>

Resumen

16. CONCURRENCIA SIN PREOCUPACIÓN

Uso de hilos para ejecutar código simultáneamente

Creación de nuevos hilos con spawn

Situación en espera de que finalicen todos los hilos mediante el uso de join Handles

Uso en hilos de closures con move

Uso del paso de mensajes para transferir datos entre hilos

Canales y transferencia de propiedad

Envío de múltiples valores y observación de la espera del receptor

Creación de varios productores mediante la clonación del transmisor

Concurrencia de estados compartidos

Uso de mutex para permitir el acceso a los datos desde un hilo cada vez

Similitudes entre RefCell<T>/Rc<T> y Mutex<T>/Arc<T>

Concurrencia ampliable con los traits Send y Sync

Cómo permitir la transferencia de propiedad entre hilos con Send

Cómo permitir el acceso desde varios hilos con Sync

Las implementaciones manuales de Send y Sync no son seguras

Resumen

17. CARACTERÍSTICAS DE LA PROGRAMACIÓN ORIENTADA A OBJETOS

Características de los lenguajes orientados a objetos

Los objetos contienen datos y comportamientos

La encapsulación que oculta los detalles de implementación

La herencia como sistema de tipos y como compartición de código

Uso de objetos trait que permiten valores de diferentes tipos

Definición de trait para un comportamiento común

Implementación de trait

Los objetos trait realizan despacho dinámico

Implementación de un patrón de diseño orientado a objetos

Definición de la entrada (Post) y creación de una nueva instancia de Post en estado de borrador

Almacenamiento del texto correspondiente al contenido de la entrada

Cómo garantizar que el contenido del borrador de la entrada esté vacío

La solicitud de revisión cambia el estado de la entrada

Adición de approve para cambiar el comportamiento de content

Contrapartidas del patrón de estado

Resumen

18. PATRONES Y COINCIDENCIAS

Partes del código donde se pueden utilizar patrones

Ramas match

Expresiones if let condicionales

Bucles condicionales con while let

Bucles for

Sentencias let

Parámetros de funciones

Refutabilidad: un patrón puede fallar al hacerlo coincidir

Sintaxis de patrones

Literales coincidentes

Coincidencia de variables con nombre

Varios patrones

Coincidenca con rangos de valores usando ..=

Desestructuración para descomponer valores

Cómo ignorar valores en un patrón

Condicionales adicionales utilizando guardas de coincidencia

Vinculaciones con @

Resumen

19. CARACTERÍSTICAS AVANZADAS

Rust no seguro

Superpoderes no seguros

Desreferenciación de un puntero sin procesar

Llamada a una función o método no seguros

Acceso o modificación de una variable estática mutable

Implementación de un trait no seguro

Acceso a los campos de una unión

Cuándo usar código no seguro

Traits avanzados

Tipos asocidos

Parámetros de tipo genérico por defecto y sobrecarga de operadores

Desambiguación entre métodos con el mismo nombre

Uso de supertraits

Uso del patrón newtype para implementar traits externos

Tipos avanzados

Uso del patrón newtype para la seguridad y abstracción de tipos

Creación de sinónimos de tipos con alias de tipos

El tipo never que nunca retorna un valor

Tipos de tamaño dinámico y el trait Sized

Funciones avanzadas y closures

Punteros a funciones

Closures de retorno

Macros

Diferencias entre macros y funciones

Macros declarativas con macro_rules! para metaprogramación en general

Macros procedimentales para generar código a partir de atributos

Cómo escribir una macro derive personalizada

Macros de tipo atributo

Macros de tipo función

Resumen

20. PROYECTO FINAL: CREACIÓN DE UN SERVIDOR WEB MULTIHILO

Creación de un servidor web de un solo hilo

Escucha de la conexión TCP

Lectura de la solicitud

Una mirada más de cerca a una petición HTTP

Escritura de una respuesta

Devolución de HTML real

Validación de la petición y respuesta selectiva

Un toque de refactorización

Conversión del servidor monohilo en servidor multihilo

Simulación de peticiones lentas

Mejora del rendimiento con thread pool

Apagado y limpieza con elegancia

Implementación del trait Drop en ThreadPool

Señalización a los hilos para que dejen de escuchar trabajos

Resumen

A. PALABRAS CLAVE

Palabras clave actualmente en uso

Palabras clave reservadas para su uso en el futuro

Identificadores sin procesar

B. OPERADORES Y SÍMBOLOS

Operadores

Símbolos que no son de operador

C. TRAITS DERIVABLES

Debug de la salida para el programador

PartialEq y Eq para comparaciones de igualdad

PartialOrd y Ord para ordenar comparaciones

Clonación y copia para duplicar valores

Hash para asignar un valor a un valor de tamaño fijo

Default para valores predeterminados

D. HERRAMIENTAS ÚTILES DE DESARROLLO

Formateo automático con rustfmt

Arregle el código con rustfix

Más lints con Clippy

Integración del IDE mediante rust-analyzer

E. EDICIONES

PRÓLOGO

No siempre estuvo tan claro, pero el lenguaje de programación Rust trata fundamentalmente de la capacitación: no importa qué tipo de código escriba ahora, Rust le capacita para llegar más lejos, para programar con confianza en una mayor variedad de dominios de lo que lo hacía antes.

Tomemos, por ejemplo, el trabajo «a nivel de sistemas», que se ocupa de detalles de bajo nivel de gestión de memoria, representación de datos y concurrencia. Tradicionalmente, esta área de la programación se considera como algo arcano, accesible solo a unos pocos elegidos que han dedicado los años necesarios a aprenderla para evitar sus tristemente célebres obstáculos. E incluso quienes lo practican lo hacen con precaución, para evitar que su código esté expuesto a vulnerabilidades, bloqueos o corrupción.

Rust rompe estas barreras eliminando las viejas trampas y proporcionando un conjunto amigable y perfeccionado de herramientas para ayudarle a lo largo del camino. Los programadores que necesiten «sumergirse» en el control de bajo nivel pueden hacerlo con Rust, sin asumir el riesgo habitual de fallos o agujeros de seguridad y sin tener que aprender las sutilezas de una cadena de herramientas voluble. Mejor aún, el lenguaje está diseñado para guiarle de forma natural hacia un código fiable y eficiente en términos de velocidad y uso de memoria.

Los programadores que ya trabajan con código de bajo nivel pueden utilizar Rust para aumentar sus aspiraciones. Por ejemplo, la introducción del paralelismo en Rust es una operación de riesgo relativamente bajo: el compilador detectará los errores clásicos por usted. Y puede abordar optimizaciones más agresivas en su código con la confianza de que no introducirá accidentalmente bloqueos o vulnerabilidades.

Pero Rust no se limita a la programación de sistemas de bajo nivel. Es lo suficientemente expresivo y ergonómico como para hacer que las aplicaciones CLI, servidores web y muchos otros tipos de código sean bastante agradables de escribir (encontrará ejemplos sencillos más adelante en el libro). Trabajar con Rust le permite desarrollar habilidades que se transfieren de un dominio a otro; puede aprender Rust escribiendo una aplicación web, y luego aplicar esas mismas habilidades a su Raspberry Pi.

Este libro adopta plenamente el potencial de Rust para capacitar a sus usuarios. Es un texto amigable y accesible destinado a ayudarle a mejorar no solo sus conocimientos de Rust, sino también su alcance y confianza como programador en general. Así que sumérjase, prepárese para aprender y ¡bienvenido a la comunidad Rust!

Nicholas Matsakis y Aaron Turon

PREFACIO

Esta versión del texto asume que está usando Rust 1.62.0 (publicado el 30 de junio de 2022) o posterior con edition="2021" en el archivo Cargo. toml de todos los proyectos para configurarlos con la idea de usar los modismos de la edición Rust 2021. Consulte «Instalación», en la página 1, para obtener instrucciones sobre cómo instalar o actualizar Rust, y consulte el Apéndice E para obtener información sobre las ediciones.

La edición 2021 del lenguaje Rust incluye una serie de mejoras que hacen a Rust más ergonómico y que corrigen algunas inconsistencias. Además de una actualización general para reflejar estas mejoras, esta versión del libro tiene una serie de mejoras para responder a comentarios específicos:

• El capítulo 7 contiene una nueva sección de referencia rápida sobre la organización del código en varios archivos con módulos.

• El capítulo 13 contiene ejemplos de closures nuevos y mejorados que ilustran más claramente las capturas, la palabra clave move y los traits Fn.

• Hemos corregido una serie de pequeños errores e imprecisiones en el libro. ¡Gracias a los lectores que nos los han comunicado!

Hay que tener en cuenta que cualquier código de versiones anteriores de este libro que compile continuará compilando con la edición correspondiente en el archivo Cargo.toml del proyecto, incluso si actualiza la versión del compilador de Rust que está utilizando. ¡Así funcionan las garantías de retrocompatibilidad de Rust!

AGRADECIMIENTOS

Queremos dar las gracias a todos los que han trabajado en el lenguaje Rust, por crear un lenguaje increíble sobre el que merece la pena escribir un libro. Damos las gracias a todos los miembros de la comunidad Rust por ser acogedores y crear un entorno en el que merece la pena recibir a más gente.

Estamos especialmente agradecidos a todos los que leyeron las primeras versiones de este libro en línea y aportaron comentarios, informes de errores y solicitudes de extracción. Un agradecimiento especial a Eduard-Mihai Burtescu, Alex Crichton y JT por la revisión técnica, y a Karen Rustad Tölva por lo artístico de la portada. Gracias a nuestro equipo de No Starch, incluidos Bill Pollock, Liz Chadwick y Janelle Ludowise, por mejorar este libro y llevarlo a la imprenta.

Carol agradece la oportunidad de haber trabajado en este libro. Agradece a su familia su constante amor y apoyo, especialmente a su marido Jake Goulding y a su hija Vivian.

INTRODUCCIÓN

Bienvenido al libro de introducción a Rust Lenguaje de programación Rust. El lenguaje de programación Rust le ayudará a escribir software de forma más rápida y confiable. La ergonomía de alto nivel y el control de bajo nivel suelen estar en conflicto en el diseño de lenguajes de programación; Rust desafía ese conflicto. A través del equilibrio entre una potente capacidad técnica y la gran experiencia de los desarrolladores, Rust le proporciona la opción de controlar detalles de bajo nivel (como la utilización de la memoria) sin todos los inconvenientes tradicionalmente asociados a dicho control.

A quién le interesa Rust

Rust es ideal para muchas personas por varias razones. Veamos algunos de los grupos más importantes a quienes les puede interesar.

Equipos de desarrolladores

Rust está demostrando ser una herramienta productiva para la colaboración entre equipos formados por un gran número de desarrolladores con diferentes niveles de conocimiento en programación de sistemas. El código de bajo nivel es propenso a diversos errores sutiles que, en la mayoría de lenguajes, solo pueden detectarse a través de pruebas exhaustivas y revisiones de código cuidadosas por parte de desarrolladores experimentados. En Rust, el compilador cumple el papel de guardián al negarse a compilar código con estos errores difíciles de encontrar, incluyendo los errores de concurrencia. Al trabajar junto al compilador, el equipo puede dedicar su tiempo a enfocarse en la lógica del programa en lugar de perseguir errores.

Rust también incorpora las últimas herramientas de desarrollo del mundo de la programación de sistemas.

• Cargo, el gestor de dependencias y la herramienta de construcción (compilación más otras actividades) incluida, facilita la adición, compilación y gestión de dependencias de forma sencilla y consistente en todo el ecosistema de Rust.

• La herramienta de formateo rustfmt garantiza un estilo de codificación consistente entre los desarrolladores.

• El Rust Language Server proporciona la integración del entorno de desarrollo integrado (IDE) para la finalización de código (o autocompletar) y para mostrar mensajes de error en línea.

Con la utilización de estas y otras herramientas en el ecosistema de Rust, los desarrolladores pueden ser más productivos al escribir código a nivel de sistema.

Estudiantes

Rust está destinado a estudiantes y a aquellos interesados en aprender sobre conceptos de sistemas. Al utilizar Rust, muchas personas han aprendido sobre temas como el desarrollo de sistemas operativos. La comunidad es muy acogedora y está dispuesta a responder las preguntas que formulan los estudiantes. A través de esfuerzos como es el caso de este libro, los equipos de Rust desean que los conceptos de sistemas sean más accesibles para un mayor número de personas, especialmente aquellos que son nuevos en programación.

Empresas

Cientos de empresas, grandes y pequeñas, utilizan Rust en producción para realizar una gran variedad de tareas, como son las herramientas de línea de comandos, servicios web, herramientas de DevOps, dispositivos integrados, análisis y transcodificación de audio y vídeo, criptomonedas, bioinformática, motores de búsqueda, aplicaciones de Internet de las cosas, aprendizaje automático e incluso partes importantes del navegador web Firefox.

Desarrolladores de código abierto

Rust es para personas que quieren construir el lenguaje de programación Rust, la comunidad, las herramientas para desarrolladores y las bibliotecas. Nos encantaría que usted contribuyera al lenguaje Rust.

Personas que valoran la rapidez y la estabilidad

Rust es para la gente que anhela velocidad y estabilidad en un lenguaje. Por velocidad nos referimos tanto a la rapidez con la que puede ejecutarse el código Rust como a la velocidad a la que Rust le permite escribir programas. Las comprobaciones del compilador de Rust garantizan la estabilidad mediante la adición de características y la refactorización. Esto contrasta con el frágil código heredado de los lenguajes sin estas comprobaciones, que los desarrolladores a menudo temen modificar. Al esforzarse por conseguir abstracciones de coste cero (características de alto nivel que se compilan en código de bajo nivel tan rápido como el código escrito manualmente), Rust se esfuerza por hacer que el código seguro sea también un código rápido.

El lenguaje Rust espera apoyar también a muchos otros usuarios; los mencionados aquí son solo algunos de los principales interesados. En general, la mayor ambición de Rust es eliminar las contrapartidas que los programadores han aceptado durante décadas, proporcionando seguridad y productividad, velocidad y ergonomía. Dele una oportunidad a Rust y compruebe si las opciones que ofrece funcionan para usted.

A quién va dirigido el libro

En el libro se presupone que usted ha escrito código en otro lenguaje de programación, aunque no se hace ninguna suposición sobre cuál. Hemos intentado que el material sea ampliamente accesible para personas con una amplia variedad de conocimientos de programación. No dedicamos mucho tiempo a explicar qué es la programación o cómo pensar en ella. Si es nuevo en programación, le vendrá mejor leer un libro que proporcione específicamente una introducción a la programación.

Cómo utilizar el libro

En general, se da por supuesto que el libro se lee de principio a fin. Los capítulos posteriores se basan en conceptos tratados anteriormente, y puede que los primeros no profundicen en un tema concreto pero lo retomen en un capítulo posterior.

Encontrará dos tipos de capítulo en este libro: capítulos de concepto y capítulos de proyecto. En los capítulos de concepto, aprenderá sobre un aspecto de Rust. En los capítulos de proyectos, crearemos pequeños programas juntos, aplicando lo que haya aprendido hasta ese momento. Los Capítulos 2, 12 y 20 son capítulos de proyectos; el resto son capítulos de conceptos.

El Capítulo 1 explica cómo instalar Rust, cómo escribir el programa "Hello, world!" y cómo utilizar Cargo, el gestor de paquetes y la herramienta de construcción de Rust. El Capítulo 2 es una introducción práctica a la escritura de un programa en Rust, en la que se crea un juego de adivinanza de números. Aquí, tratamos conceptos a alto nivel, y los capítulos posteriores proporcionarán detalles adicionales. Si quiere ensuciarse las manos de inmediato, el Capítulo 2 es el lugar adecuado. El Capítulo 3 trata las características de Rust que son similares a las de otros lenguajes de programación, y en el Capítulo 4 aprenderá sobre el sistema de propiedad de Rust. Si es un aprendiz particularmente meticuloso que prefiere aprender cada detalle antes de pasar al siguiente, puede que quiera saltarse el Capítulo 2 e ir directamente al Capítulo 3, y volver al Capítulo 2 cuando quiera trabajar en un proyecto aplicando los detalles que ha aprendido.

En el Capítulo 5 se discuten las structs y los métodos, y en el Capítulo 6 se tratan las enums, las expresiones match, y la construcción de control de flujo if let. Usará structs y enums para hacer tipos personalizados en Rust.

En el Capítulo 7, aprenderá sobre el sistema de módulos de Rust y sobre las reglas de privacidad para organizar el código y la interfaz pública de programación de aplicaciones (API). En el Capítulo 8 se discuten algunas estructuras de datos de colección habituales que la biblioteca estándar proporciona, tales como vectores, cadenas y mapas hash. El Capítulo 9 explora la filosofía y las técnicas de gestión de errores de Rust.

El Capítulo 10 profundiza en los genéricos, los traits (rasgos) y los lifetimes (tiempos de vida), que le dan el poder de definir código que se aplica a varios tipos. En el Capítulo 11 se tratan las pruebas, que incluso con las garantías de seguridad de Rust son necesarias para asegurar que la lógica del programa es correcta. En el Capítulo 12, construiremos nuestra propia implementación de un subconjunto de funcionalidades de la herramienta de línea de comandos grep que busca texto dentro de archivos. Para esto, usaremos muchos de los conceptos que discutimos en los capítulos anteriores.

El Capítulo 13 explora los closures (cierres) e iteradores: características de Rust que provienen de los lenguajes de programación funcionales. En el Capítulo 14, examinaremos Cargo más a fondo y hablaremos de las mejores prácticas para compartir sus bibliotecas con otros usuarios. En el Capítulo 15 se analizan los punteros inteligentes que proporciona la biblioteca estándar y los traits que permiten su funcionalidad.

En el Capítulo 16, recorreremos diferentes modelos de programación concurrente y hablaremos de cómo Rust le ayuda a programar en múltiples hilos sin preocupación. En el Capítulo 17 se examina cómo los modismos de Rust se comparan con los principios de programación orientada a objetos con los que podría estar familiarizado.

El Capítulo 18 es una referencia sobre patrones y concordancia de patrones, que son poderosas formas de expresar ideas a través de los programas de Rust. El Capítulo 19 contiene una mezcla de temas avanzados de interés, incluyendo Rust no seguro, macros, y otros sobre lifetimes, traits, tipos, funciones y closures.

En el Capítulo 20, completaremos un proyecto en el que implementaremos un servidor web multihilo de bajo nivel.

Por último, algunos apéndices contienen información útil sobre el lenguaje en un formato más parecido a una referencia. En el Apéndice A se tratan las palabras clave de Rust, el Apédice B se ocupa de los operadores y símbolos de Rust, en el Apéndice C se tratan los traits derivables proporcionados por la biblioteca estándar, el Apéndice D se encarga de presentar algunas herramientas de desarrollo que son de utilidad, y en el Apéndice E se explican las ediciones de Rust.

No hay una forma incorrecta de leer este libro: si quiere saltarse algo, ¡hágalo! Es posible que tenga que volver a capítulos anteriores si experimenta alguna confusión. Pero haga lo que más le convenga.

Una parte importante del proceso de aprendizaje de Rust es aprender a leer los mensajes de error que muestra el compilador: estos le guiarán hacia un código funcional. Por lo tanto, proporcionaremos muchos ejemplos que no compilan junto con el mensaje de error que el compilador le mostrará en cada situación. Sepa que si introduce y ejecuta un ejemplo al azar, ¡puede que no compile! Asegúrese de leer el texto anexo para ver si el ejemplo que está intentando ejecutar está destinado a dar error. En la mayoría de las situaciones, le guiaremos a la versión correcta de cualquier código que no compile.

Recursos y cómo contribuir al libro

Este libro es de código abierto. Si encuentra algún error, no dude en enviar una incidencia o una pull request (solicitud de extracción) a GitHub en https://github.com/rust-lang/book. Para más información, consulte CONTRIBUTING.md en https://github.com/rust-lang/book/blob/main/CONTRIBUTING.md.

El código fuente de los ejemplos de este libro, las erratas y otra información están disponibles en https://nostarch.com/rust-programming-language-2nd-edition.

1

EMPEZAMOS

¡Comencemos su viaje a través de Rust! Hay mucho que aprender, pero todo recorrido debe comenzar en algún punto. En este capítulo, trataremos:

• Cómo instalar Rust en Linux, macOS, y Windows.

• Cómo escribir un programa que imprima Hello, world!

• Cómo usar cargo, y el sistema de construcción y administración de paquetes de Rust.

Instalación

El primer paso es la instalación de Rust. Descargaremos Rust utilizando rustup, una herramienta de línea de comandos para gestionar versiones de Rust y herramientas asociadas. Necesitará una conexión a Internet para la descarga.

NOTA

Si decide no utilizar rustup por alguna razón, por favor visite la página Other Rust Installation Methods enhttps://forge.rust-lang.org/infra/other-installation-methods.html, donde podrá disponer de otras opciones.

Mediante los siguientes pasos se instala la última versión estable del compilador de Rust. Las garantías de estabilidad de Rust aseguran que todos los ejemplos del libro que compilen continuarán compilando con versiones más recientes de Rust. El resultado puede diferir ligeramente entre las distintas versiones porque Rust mejora frecuentemente los mensajes de error y las advertencias. En otras palabras, cualquier versión más reciente y estable de Rust que instale siguiendo estos pasos debería funcionar como se espera con el contenido del libro.

NOTACIÓN DE LINEA DE COMANDOS

En este capítulo, y a lo largo del libro, mostraremos algunos comandos que se usan utilizando el terminal. Las líneas que debe teclear en el terminal comienzan todas con $. No es necesario que escriba el carácter $; es el símbolo del sistema que se muestra para indicar el inicio de cada comando. Las líneas que no comienzan con $ generalmente muestran el resultado del comando anterior. Por otra parte, en los ejemplos específicos de PowerShell se utilizará > en lugar de $.

Instalación de rustup en Linux o macOS

Si utiliza Linux o macOS, abra el terminal y teclee el siguiente comando:

El comando descarga un script y comienza la instalación de la herramienta rustup, que instala la última versión estable de Rust. Es posible que se le solicite una contraseña. Si la instalación tiene éxito, aparecerá la siguiente línea:

También necesitará un enlazador (linker), que es un programa que Rust utiliza para unir los resultados compilados en un archivo. Es probable que ya tenga uno. Si aparecen errores con el enlazador, deberá instalar un compilador de C, que normalmente incluirá un enlazador. El compilador de C también es útil porque algunos de los paquetes de uso más frecuente de Rust dependen del código C y requerirán un compilador de C

En macOS, puede obtener el compilador de C ejecutando lo siguiente:

Los usuarios de Linux generalmente deberán instalar GCC o Clang, dependiendo de la documentación de cada distribución. Por ejemplo, si usa Ubuntu, puede instalar el paquete build-essential.

Instalación de rustup en Windows

Para Windows, vaya a https://www.rust-lang.org/tools/install y siga las instrucciones para instalar Rust. En algún momento de la instalación, recibirá un mensaje explicando que también necesitará las herramientas de construcción MSVC para Visual Studio 2013 o posterior.

Para obtener las herramientas de construcción, deberá instalar Visual Studio 2022 desde https://visualstudio.microsoft.com/downloads. Cuando se le pregunte qué cargas de trabajo instalar, incluya:

• Desktop Development con C++”

• Windows 10 u 11 SDK

• El componente del paquete de idioma inglés, junto con cualquier otro paquete de idioma que elija.

En el resto del libro se utilizan comandos que funcionan tanto en cmd.exe como en PowerShell. En el caso de que existan diferencias específicas, explicaremos cuál de ellos usar.

Solución de problemas

Para verificar que Rush se ha instalado correctamente, abra el terminal y teclee la siguiente línea:

Debería ver el número de versión, el hash del commit (hash de confirmación de cambios) y la fecha del commit de la última versión estable que se ha lanzado, en el siguiente formato:

Si ve esta información, ¡ha instalado Rust correctamente! Si no la ve, verifique que Rust esté en su variable de sistema %PATH% tal como explicamos a continuación.

En Windows CMD, use:

En PowerShell, use:

En Linux y macOS, use:

Si todo está correcto y Rust aún no funciona, hay varios recursos con los que puede obtener ayuda. Descubra cómo ponerse en contacto con otros programadores de Rust (o rustaceans, un apodo divertido que nos ponemos a nosotros mismos) en la página de la comunidad: https://www.rust-lang.org/community.

Actualización y desinstalación

Una vez que Rust esté instalado mediante rustup, actualizarlo a una versión recién lanzada es fácil. Desde el terminal, ejecute el siguiente script de actualización:

Para desinstalar Rust y rustup, ejecute el siguiente script de desinstalación desde su terminal:

Documentación local

La instalación de Rust también incluye una copia local de la documentación para que pueda leerla sin conexión. Ejecute rustup doc para abrir la documentación local en su navegador.

Cada vez que se proporcione un tipo o una función por parte de la biblioteca estándar y no esté seguro de lo que hace o de cómo usarlo, consulte la documentación de la interfaz de programación de aplicaciones (API) para averiguarlo.

Hello, World!

Ahora que ha instalado Rust, es hora de escribir su primer programa en Rust. Es tradición, al aprender un nuevo lenguaje, escribir un pequeño programa que imprima el texto Hello, world! en la pantalla, así que ¡haremos lo mismo aquí!

NOTA

En el libro, se supone que el lector está familiarizado de alguna manera con la línea de comandos. Rust no impone normas específicas sobre su entorno de edición o herramientas, o sobre dónde debe residir su código, por lo que si prefiere usar un entorno de desarrollo integrado (IDE) en lugar de la línea de comandos, puede utilizar su IDE favorito. Muchos IDE ahora tienen, en alguna medida, un soporte para Rust; consulte la documentación del IDE para obtener más detalles. El equipo de Rust se ha enfocado en habilitar un excelente soporte de IDE mediante rust-analyzer. Vea el Apéndice D para ampliar detalles.

Creación de un directorio de proyectos

Comenzaremos creando un directorio para almacenar el código de Rust. Para Rust es indiferente dónde se encuentre ubicado el código, pero para los ejercicios y proyectos del libro sugerimos crear un directorio llamado projects en su directorio principal y almacenar allí todos sus proyectos.

Abra el terminal y teclee los comandos que veremos a continuación para crear el directorio projects y un directorio para el proyecto «Hello, world!» dentro del directorio projects.

Para Linux, macOS y PowerShell en Windows, introduzca lo siguiente:

Para Windows CMD, introduzca lo siguiente:

Escritura y ejecución de un programa en Rust

A continuación, cree un nuevo archivo fuente y llámelo main.rs. Los archivos de Rust siempre terminan con la extensión .rs. Si utiliza más de una palabra en el nombre del archivo, la convención es usar un guion bajo para separarlas. Por ejemplo, utilice hello_world.rs en lugar de helloworld.rs.

Ahora, abra el archivo main.rs que acaba de crear e introduzca el código del Listado 1-1.

Listado 1-1: Programa que presenta en pantalla Hello, world!

Guarde el archivo y vuelva a la ventana del terminal en el directorio ~/projects/hello_world. En Linux o macOS, introduzca los siguientes comandos para compilar y ejecutar el archivo:

En Windows, introduzca el comando .\main.exe en lugar de./main:

Independientemente de su sistema operativo, la cadena Hello, world! debería aparecer en el terminal. Si no aparece esta salida, consulte la sección «Solución de problemas» para obtener ayuda.

Si ha aparecido Hello, world!, ¡felicidades! Ha escrito oficialmente un programa en Rust. ¡Eso le convierte en programador de Rust! ¡Bienvenido!

Anatomía de un programa en Rust

Repasemos en detalle el programa «Hello, world!». Aquí está la primera pieza del rompecabezas:

Estas líneas definen una función llamada main. La función main es especial: siempre es el primer código que se ejecuta en cada programa ejecutable de Rust. Aquí, la primera línea declara una función llamada main que no tiene parámetros y no devuelve nada. Si hubiera parámetros, se colocarían dentro del paréntesis ().

El cuerpo de la función está encerrado entre llaves {}. Rust requiere que todos los cuerpos de las funciones se encierren entre llaves. Es una buena práctica colocar la llave de apertura en la misma línea que la declaración de la función, añadiendo un espacio entre ellas.

NOTA

Si desea mantener un estilo estándar en sus proyectos de Rust, puede utilizar una herramienta de formateo automático llamada rustfmt para formatear su código en un estilo particular (en el Apéndice D se amplía la información sobre rustfmt). El equipo de Rust ha incluido esta herramienta en la distribución estándar de Rust, al igual que rustc, por lo que debería estar instalada en su ordenador.

El cuerpo de la función main contiene el siguiente código:

Esta línea hace todo el trabajo en este pequeño programa; presenta el texto en la pantalla. Aquí hay cuatro detalles importantes que hay que tener en cuenta.

Primero, el estilo de Rust es hacer el sangrado con cuatro espacios, no con una tabulación.

Segundo, println! llama a una macro en Rust. Si se tratara de una función, se escribiría como println (sin el signo !). Discutiremos las macros en Rust con más detalle en el Capítulo 19. Por ahora, solo necesita saber que el uso de ! significa que está llamando a una macro en lugar de tratarse de una función normal y que las macros no siempre siguen las mismas reglas que las funciones.

Tercero, puede ver la cadena "Hello, world!". Pasamos esta cadena como argumento a println!, y la cadena se presenta en pantalla.

Cuarto, terminamos la línea con un punto y coma (;), lo cual indica que esta expresión ha terminado y que la siguiente está lista para comenzar. La mayoría de las líneas de código en Rust terminan con un punto y coma.

Compilación y ejecución son pasos separados

Acaba de ejecutar el programa recién creado, así que examinemos cada paso del proceso.

Antes de ejecutar un programa en Rust, debe compilarlo utilizando el compilador de Rust, introduciendo el comando rustc y pasando el nombre de su archivo fuente, de la siguiente manera:

Si tiene experiencia en C o C++, notará que lo anterior es similar a gcc o clang. Después de realizar con éxito la compilación, Rust genera un ejecutable binario.

En Linux, macOS y PowerShell en Windows, puede ver el ejecutable tecleando el comando ls en su shell:

En Linux y macOS, verá dos archivos. Con PowerShell en Windows, verá los mismos tres archivos que vería utilizando CMD. Con CMD en Windows, teclearía lo siguiente:

Lo anterior muestra el archivo del código fuente con la extensión .rs, el archivo ejecutable (main.exe en Windows, pero main en todas las demás plataformas) y, al usar Windows, el archivo que contiene información de depuración con la extension .pdb. A partir de aquí, se ejecuta el archivo main o main.exe de la siguiente manera:

Si su main.rs es el programa “Hello, world!”, esta línea presenta Hello, world! en su terminal.

Si está más familiarizado con un lenguaje de programación dinámico como Ruby, Python o JavaScript, es posible que no esté acostumbrado a compilar y ejecutar un programa en pasos separados.

Rust es un lenguaje compilado de antemano, lo que significa que usted puede compilar un programa y proporcionarle el ejecutable a otros, y ellos podrán ejecutarlo incluso sin tener Rust instalado. En cambio, si le da a alguien un archivo .rb, .py, o .js, esa persona necesitará tener instalada una implementación de Ruby, Python o JavaScript (respectivamente). Pero en esos lenguajes, solo se necesita un comando para compilar y ejecutar el programa. Todo es una cuestion de compromiso con el diseño de lenguajes.

Compilar usando solamente rustc es suficiente para programas sencillos, pero a medida que su proyecto crezca, querrá gestionar todas las opciones y facilitar la compartición de su código. A continuación, presentaremos la herramienta Cargo, que le ayudará a escribir programas en Rust para el mundo real.

¡Hola, Cargo!

Cargo es el sistema de construcción y el gestor de paquetes de Rust. La mayoría de los programadores de Rust utilizan esta herramienta para administrar sus proyectos de Rust, porque Cargo puede hacer muchas tareas por usted, como compilar el código, descargar las bibliotecas de las que el código depende y compilar esas bibliotecas. Llamamos dependencias a las bibliotecas que su código necesita.

Los programas más sencillos en Rust, como el que hemos escrito hasta ahora, no tienen dependencias. Si hubiéramos compilado el proyecto «Hello, world!» con Cargo, solo se utilizaría la parte de Cargo que maneja la compilación del código. A medida que escriba programas en Rust más complejos, añadirá dependencias, y si comienza un proyecto utilizando Cargo, será mucho más fácil añadir dependencias.

Debido a que la gran mayoría de los proyectos en Rust utilizan Cargo, en el resto del libro se supone que usted también lo utilizará. Cargo viene instalado con Rust si ha utilizado los instaladores oficiales mencionados en «Instalación». Si ha instalado Rust de alguna otra manera, verifique si Cargo está instalado tecleando lo siguiente en el terminal:

Si ve un número de versión, ¡lo tiene! Si ve un error, como command not found, consulte la documentación de su método de instalación para determinar cómo instalar Cargo por separado.

Creación de un proyecto con Cargo

Vamos a crear un nuevo proyecto utilizando Cargo y vamos a ver cómo difiere de nuestro proyecto original «Hello, world!». Navegue de vuelta a su directorio projects (o donde haya decidido almacenar su código). Luego, en cualquier sistema operativo, ejecute lo siguiente:

El primer comando crea un nuevo directorio y proyecto llamado hello_cargo. Hemos nombrado nuestro proyecto como hello_cargo, y Cargo crea sus archivos en un directorio con el mismo nombre.

Entre en el directorio hello_cargo y liste los archivos. Verá que Cargo ha generado dos archivos y un directorio (en lugar de tener que hacerlo nosotros): un archivo Cargo.toml y un directorio src que contiene el archivo main.rs.

También ha inicializado un nuevo repositorio Git junto con un archivo .gitignore. Los archivos de Git no se generarán si ejecuta cargo new dentro de un repositorio Git existente; puede anular este comportamiento utilizando cargo new --vcs=git.

NOTA

Git es un sistema muy utilizado de control de versiones. Puede cambiar cargo new para utilizar un sistema de control de versiones diferente o ningún sistema de control de versiones utilizando la bandera --vcs. Ejecute cargo new --help para ver las opciones disponibles.

Abra Cargo.toml en el editor de texto que haya elegido. Debería ser similar al código del Listado 1-2.

Listado 1-2: Contenido de Cargo.toml generado por cargo new.

Este archivo está en formato TOML (Tom’s Obvious, Minimal Language), que es el formato de configuración de Cargo.

La primera línea, [package], es un encabezado de sección que indica que las declaraciones siguientes configuran un paquete. A medida que añadamos más información a este archivo, añadiremos otras secciones.

En las tres líneas siguientes se determina la información de configuración que Cargo necesita para compilar el programa: el nombre, la versión y la edición de Rust a utilizar. Hablaremos sobre la clave edition en el Apéndice E.

La última línea, [dependencies], es el inicio de una sección donde se pueden listar las dependencias del proyecto. En Rust, los paquetes de código se conocen como crates. No necesitaremos otros crates para este proyecto, pero los utilizaremos en el primer proyecto del Capítulo 2, por lo que utilizaremos esta sección de dependencias en ese momento.

Ahora abra src/main.rs y eche un vistazo:

Cargo ha generado un programa «Hello, World!» por usted, ¡exactamente como el que escribimos en el Listado 1-1! Hasta ahora, las diferencias entre nuestro proyecto y el proyecto generado por Cargo son que Cargo ha colocado el código en el directorio src y tenemos un archivo de configuración Cargo.toml en el directorio principal.

Cargo espera que los archivos fuente de su proyecto se encuentren dentro del directorio src. El directorio del proyecto de nivel superior es solo para archivos README, información de licencia, archivos de configuración y cualquier otra cosa que no esté relacionada con el código de su proyecto. El uso de Cargo le ayuda a organizar sus proyectos. Hay un lugar para todo, y todo está en su lugar.

Si ha iniciado un proyecto que no utiliza Cargo, como hicimos con el proyecto «Hello, World!», puede convertirlo en un proyecto que sí use Cargo. Mueva el código del proyecto al directorio src y cree el archivo Cargo.toml adecuado.

Construcción y ejecución de un proyecto con Cargo

Ahora ¡veamos qué cambia cuando construimos y ejecutamos el programa «Hello, world!» con Cargo! Desde su directorio hello_cargo, construya su proyecto tecleando el siguiente comando:

Este comando crea un archivo ejecutable en target/debug/hello_ cargo (o target\debug\hello_cargo.exe en Windows), en lugar de hacerlo en su directorio actual. Debido a que la construcción predeterminada es una construcción de depuración, Cargo coloca el binario en un directorio llamado debug. Puede ejecutar el archivo ejecutable con el siguiente comando:

Si todo va bien, Hello, world! debería aparecer en el terminal. Ejecutar cargo build por primera vez también hace que Cargo cree un nuevo archivo en el nivel superior: Cargo.lock. Este archivo realiza un seguimiento de las versiones exactas de las dependencias del proyecto. Como este proyecto no tiene dependencias, el archivo está casi vacío. Nunca necesitará cambiar este archivo manualmente; Cargo gestiona su contenido por usted.

Acabamos de construir un proyecto con cargo build y lo ejecutamos con ./target/debug/hello_cargo, pero también podemos utilizar cargo run para compilar el código y luego ejecutar el ejecutable resultante, todo en un solo comando:

Utilizar cargo run es más conveniente que tener que acordarse de ejecutar cargo build y luego usar la ruta completa hacia el binario, por lo que la mayoría de los desarrolladores utilizan cargo run.

Observe que esta vez no vimos una salida que indicara que Cargo estaba compilando hello_cargo. Cargo ha determinado que los archivos no han cambiado, por lo que no ha vuelto a construir el proyecto antes de ejecutar el binario. Si hubiera modificado su código fuente, Cargo habría vuelto a compilar el proyecto antes de ejecutarlo, y habría visto esta salida:

Cargo también proporciona el comando llamado cargo check. Este comando verifica rápidamente el código para asegurarse de que compila correctamente, pero no produce un ejecutable:

¿Por qué no desearía usted un ejecutable? A menudo, cargo check es mucho más rápido que cargo build porque omite el paso de producir un ejecutable. Si verifica continuamente su trabajo mientras escribe el código, ¡utilizar cargo check acelerará el proceso de informarle si su proyecto sigue compilando! Por eso, muchos desarrolladores de Rust ejecutan cargo check periódicamente mientras escriben su programa para asegurarse de que compila.

Recapitulemos lo que hemos aprendido hasta ahora sobre Cargo:

• Podemos crear un proyecto usando cargo new.

• Podemos construir un proyecto usando cargo build.

• Podemos construir y ejecutar un proyecto en un solo paso usando cargo run.

• Podemos construir un proyecto sin generar un binario para verificar errores usando cargo check.

• En lugar de guardar el resultado de la construcción en el mismo directorio que nuestro código, Cargo lo almacena en el directorio target/debug.

Una ventaja adicional de utilizar Cargo es que los comandos son los mismos sin importar el sistema operativo con el que se esté trabajando. Por lo tanto, a partir de este punto, ya no proporcionaremos instrucciones específicas para Linux y macOS frente a Windows.

Construcción para la versión de lanzamiento (Release)

Cuando su proyecto esté listo para el lanzamiento, puede utilizar cargo build --release para compilarlo con optimizaciones. Este comando creará un ejecutable en la carpeta target/release en lugar de target/debug. Las optimizaciones hacen que el código de Rust se ejecute más rápido, pero activarlas prolonga el tiempo que se tarda en compilar el programa. Por esta razón, existen dos perfiles diferentes: uno para el desarrollo, cuando se desea volver a construir rápidamente y con frecuencia, y otro para compilar el programa final que entregará a un usuario y que no volverá a compilar repetidamente y se ejecutará lo más rápidamente posible. Si evalúa el tiempo de ejecución de su código, asegúrese de ejecutar cargo build --release y de realizar las pruebas de rendimiento (benchmarking) con el ejecutable en target/release.

Cargo como convención

Con proyectos sencillos, Cargo no aporta mucho valor con respecto al uso de rustc, pero demostrará su valía a medida que sus programas se vuelvan más complejos. Una vez que los programas crecen y tienen varios archivos o necesitan dependencias, es mucho más fácil dejar que Cargo coordine la construcción.

Aunque el proyecto hello_cargo es sencillo, se utilizan ahora en él gran parte de las herramientas reales que empleará usted en el resto de su carrera en Rust. De hecho, para trabajar en cualquier proyecto existente, puede utilizar los siguientes comandos para revisar el código utilizando Git, cambiar al directorio del proyecto y construirlo:

Para obtener más información sobre Cargo, consulte la documentación en https://doc.rust-lang.org/cargo.

Resumen

¡Ya ha comenzado su viaje a través de Rust! En este capítulo, ha aprendido cómo:

• Instalar la última versión estable de Rust utilizando rustup.

• Actualizar a una versión más reciente de Rust.

• Abrir la documentación instalada localmente.

• Escribir y ejecutar el programa «Hello, World!» utilizando rustc directamente.

• Crear y ejecutar un nuevo proyecto utilizando las convenciones de Cargo.

Este es un buen momento para construir un programa más sustancial y familiarizarse con la lectura y la escritura de código Rust. En el Capítulo 2, contruiremos un programa de juego de adivinanzas. Si prefiere comenzar aprendiendo cómo funcionan los conceptos de programación más comunes en Rust, consulte el Capítulo 3 y luego regrese al Capítulo 2.

2

PROGRAMACIÓN DE UN JUEGO DE ADIVINANZAS

¡Vamos a sumergirnos en Rust trabajando juntos en un proyecto práctico! Este capítulo introduce algunos conceptos comunes de Rust, y le muestra cómo usarlos en un programa real. Aprenderá sobre let, match, métodos, funciones asociadas y crates externos, ¡entre otras cosas! En los siguientes capítulos, exploraremos estas ideas con más detalle. En este capítulo, simplemente practicará los fundamentos.

Implementaremos un problema clásico de programación para principiantes: un juego de adivinanzas. Así es como funciona: el programa generará un número entero aleatorio entre 1 y 100. A continuación, le pedirá al jugador que proponga un valor. Después de introducirlo, el programa indicará si el valor es demasiado bajo o demasiado alto. Si el valor es correcto, el juego imprimirá un mensaje de felicitación y saldrá.

Configuración de un nuevo proyecto

Para configurar un nuevo proyecto, vaya al directorio projects que creó en el Capítulo 1 y cree un nuevo proyecto utilizando Cargo, de la siguiente manera:

El primer comando, cargo new, toma el nombre del proyecto (guessing_game) como primer argumento. El segundo comando cambia al directorio del nuevo proyecto.

Observe el archivo Cargo.toml generado:

Como vio en el Capítulo 1, cargo new genera el programa «Hello, world!» por usted. Eche un vistazo al archivo src/main.rs:

Ahora vamos a compilar el programa «Hello, world!» y lo vamos a ejecutar en un solo paso utilizando el comando cargo run:

El comando run resulta útil cuando se necesita hacer iteraciones rápidas en un proyecto, como haremos en este juego, probando rápidamente cada iteración antes de pasar a la siguiente.

Abra nuevamente el archivo src/main.rs. Usted va a escribir todo el código en este archivo.

Procesamiento de una propuesta

La primera parte del programa del juego de adivinanzas solicitará la entrada por parte del usuario, procesará esa entrada y verificará que la entrada tenga la forma esperada. Para empezar, permitiremos al jugador teclear una propuesta. Introduzca ahora el código de la Lista 2-1 en src/main.rs.

Listado 2-1: Código que admite una propuesta del usuario y la imprime.

Este código contiene mucha información, así que vamos a repasarlo línea por línea. Para obtener la entrada del usuario y luego imprimir el resultado como salida, necesitamos importar la biblioteca de entrada/salida io al ámbito de nuestro programa. La biblioteca io proviene de la biblioteca estándar, conocida como std:

Por defecto, Rust tiene un conjunto de elementos definidos en la biblioteca estándar que importa automáticamente al ámbito de cada programa. Este conjunto se llama prelude, y usted puede ver todos sus elementos en https://doc.rust-lang.org/std/prelude/index.html.

Si un tipo que se desea utilizar no está en prelude, se debe importar ese tipo explícitamente al ámbito del programa con una sentencia use. Al utilizar la biblioteca std::io se obtienen una serie de características útiles, incluida la capacidad de aceptar la entrada del usuario.

Como vimos en el Capítulo 1, la función main es el punto de entrada al programa:

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

Como también aprendió en el Capítulo 1, println! es una macro que imprime una cadena en pantalla:

Este código imprime un mensaje que indica de qué trata el juego y solicita la entrada al usuario.

Almacenamiento de valores con variables

A continuación, creamos una variable para almacenar la entrada del usuario, de la siguiente manera:

¡Ahora el programa se está poniendo interesante! Es mucho lo que sucede en esta corta línea. Usamos la sentencia let para crear la variable. Aquí tiene otro ejemplo:

Esta línea crea una nueva variable llamada apples y la vincula al valor 5. En Rust, las variables son inmutables por defecto, lo que significa que una vez que le damos a la variable un valor, este no cambiará. Discutiremos este concepto en detalle en la sección «Variables y mutabilidad». Para hacer una variable mutable, añadimos mut antes del nombre de la variable:

NOTA

La sintaxis // inicia un comentario que continúa hasta el final de la línea. Rust ignora todo lo que se encuentra en los comentarios. Discutiremos los comentarios con más detalle en el Capítulo 3.

Volviendo al programa del juego de adivinanzas, usted ahora sabe que let mut guess introducirá una variable mutable llamada guess. El signo igual () le indica ahora a Rust que queremos asignar algo a la variable. A la derecha del signo igual se encuentra el valor al que guess está asignado, que es el resultado de llamar a String::new, una función que devuelve una nueva instancia de String. String es un tipo de cadena proporcionado por la biblioteca estándar codificada en UTF-8 y que puede crecer.

La sintaxis :: en la línea ::new indica que new es una función asociada del tipo String. Una función asociada es una función implementada en un tipo, en este caso String. Esta función new crea una nueva cadena vacía. Encontrará una función new en muchos tipos porque es un nombre común para una función que crea un nuevo valor de algún tipo.

Recepción de datos introducidos por el usuario

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 del módulo io, que nos permitirá manejar la entrada del usuario:

Si no hubiéramos importado la biblioteca io con use std::io; al principio del programa, aún podríamos usar la función escribiendo esta llamada a función como std::io::stdin. La función stdin devuelve una instancia de std::io::Stdin, que es un tipo que representa al handle (manejador, referenciador) de la entrada estándar para el terminal.

A continuación, la línea .read_line(&mut guess) llama al método read_line en el handle de la entrada estándar para obtener la entrada del usuario. También pasamos &mut guess como argumento a read_line