Lo hemos escuchado muchas veces, más cuando nos vemos envueltos en situaciones críticas al momento de producir software, necesitamos desarrollar herramientas que requieren ser rápidas, precisas y de bajo consumo de recursos.

Existe una cantidad vasta de lenguajes de programación, bibliotecas y frameworks que nos pueden ayudar a realizar nuestro trabajo, aun así no todos son lo que definiríamos como "La herramienta correcta" para el trabajo que necesitamos entregar en dos semanas a un cliente altamente exigente.

Cuando nos adentramos al lenguaje de programación Rust no tenemos línea alguna que nos especifique los límites de el lenguaje, pues el objetivo principal de Rust es el otorgar control, la adquisición de poder e independencia por parte del programador.

Rust cumple conos paradigmas y su naturaleza extensible permite que los programadores desarrollen sus ideas sin límites que pueden llegas a ser molestos después de lidiar una o dos veces con ellos, pensemos en lenguajes de programación como C o C++, estos dos lenguajes son las bases de mucha de la tecnología usada actualmente, la mayoría de los dispositivos que usamos cuentan con un sistema operativo escrito mayormente en C o C++, sin embargo estos lenguajes de programación no son perfectos, el control que le es ofrecido al usuario no está regulado por criterios de ningún tipo lejos de la sintaxis y algunas protecciones básicas en la memoria (sin mencionar la protección que otorga el sistema operativo en muchos casos).

Aun así los lenguajes de programación como C o C++ no poseen una regulación muy profunda, lo cual puede llevar a cometer los errores más comunes que se conocen en estos lenguajes como:

  • Memory leaks
  • Data races
  • Stack & Buffer overflow
  • Null pointers
  • Segfaults
  • etc.

Pensemos en el enfoque principal de Rust, ser un lenguaje de programación de sistemas, un nivel en el que se trabaja con un manejo avanzado de la memoria del sistema, representación extensiva de datos, concurrencia, trabajar con diferentes hilos de ejecución y más. Esto puede ser visto como algo duro o difícil pues es muy fácil cometer errores que pueden congelar, dañar parcial o totalmente un sistema funcional e incluso los programadores de sistemas con más experiencia no están libres de cometer errores menores que dejan sus programas expuestos a vulnerabilidades, cierres inesperados o corrupción de datos parcial o total.

Rust no se limita solo a programación de sistemas, al ser extremadamente modular permite aplicaciones CLI, GUI's con gtk-rs o incluso puedes desplegar tus propias web-apps utilizando rocket, un poderoso framework hecho completamente en Rust.

Incluso si eres un programador que trabaja a bajo nivel puedes reescribir tus proyectos en Rust para mejorar su tiempo de ejecución, seguridad, concurrencia o legibilidad sin miedo a introducir nuevos errores o vulnerabilidades.

En este libro comunitario aprenderás a manejar las bases del lenguaje de programación Rust, podrás aplicar tus conocimientos para mejorar o realizar nuevos proyectos, no esperes más, toma tu computadora, una libreta y empieza a aprender con nosotros.

-- Future Lab Future Lab

¡Prepara tu entorno!

¡Bienvenido! Si es tu primera vez utilizando el lenguaje de programación Rust este capítulo es para ti, antes de comenzar a escribir centenares de líneas de código necesitamos preparar nuestro entorno de desarrollo.

Este libro asume que posees conocimientos básicos de programación, si eres o te consideras un novato en esta área te recomendamos comenzar por un lenguaje más sencillo como C o Python.

Antes que nada tenemos que instalar Rust en nuestra computadora, dependiendo de nuestro sistema operativo nuestra instalación será diferente y necesitará más o menos pasos para configurarse correctamente.

Por ahora necesitaremos:

  • Una computadora
  • Acceso a Internet

En los capítulos 2.1, 2.2 y 2.3 cubriremos la instalación en diferentes sistemas operativos comunes, si ya posees Rust instalado o si consideras que puedes guiarte durante el proceso de instalación te recomendamos mirar el capítulo 2.4 para que elijas tu editor preferido o puedes saltar hacia el capítulo 3 para comenzar a trabajar en Rust.

Solo cubriremos los sistemas operativos más conocidos o más populares, siendo estos "Windows", "Mac OS" & "Gnu/Linux". No cubriremos la instalación en otro sistema unix-like, aun así, si deseas contribuir con la instalación en otro sistema operativo eres bienvenido :)

Instalación en Microsoft Windows

En este apartado instalaremos las herramientas necesarias para programar en el lenguaje de programación Rust dentro de un sistema operativo Microsoft Windows.

Instalar Rustup

Lo primero que necesitamos es rustup, el cual es un instalador del lenguaje y sus respectivas herramientas.

Sitio oficial de Rustup

Si estás en una instalación de 64 bits te recomendamos instalar utilizando el siguiente enlace.

En caso contrario puedes usar el instalador de 32 bits.

No te preocupes si resulta confuso al inicio, el instalador de Rust te guiará paso a paso en el proceso.

Si te consideras un novato en el lenguaje te recomendamos mantener los ajustes de instalación por defecto.

Si deseas empaparte con un poco más de información continúa leyendo o si consideras que la instalación es suficiente puedes pasar al siguiente capítulo.

Los canales de actualización

El desarrollo de Rust es muy activo, por lo que opera en tres canales de distribución:

  • Stable
  • Beta
  • Nightly

Si eres un usuario novel te recomendamos mantenerte en el canal Stable.

Los canales Beta o Nightly son para aquellos valientes que desean probar características más recientes del lenguaje aunque a veces son necesarios para algunas herramientas.

Vamos a explicar/traducir el proceso de liberación de Rust como viene explicado en el libro:

Necesitarás conocimientos básicos de Git para entender algunas cosas.

Cada vez que se añade una característica a Rust, se crea un commit en la rama master del repositorio. Esto pasa con frecuencia ya que la comunidad de Rust es muy activa, por lo tanto cada noche una nueva versión del canal Nightly se produce, es decir, todos los días se libera una nueva versión con el hash del último commit aceptado dentro de Nightly, la rama master durante el transcurso del día podría verse algo así:

nightly: * - - * - - *

Cada * representa un commit.

Como los ciclos de liberación son fijos cada seis semanas el equipo de desarrollo de Rust se prepara para liberar una nueva versión, antes que nada primero deben migrar los cambios, por lo que la rama beta sale de la rama master y con eso tendremos nuestra liberación beta.

nightly: * - - * - - *
                     |
beta:                *

La mayoría de los usuarios de Rust no utiliza este canal de forma activa, en su lugar utilizan Sistemas de Integración Continua para detectar cualquier posible regresión o error. Mientras esto ocurre, la rama master continúa actualizandose.

nightly: * - - * - - * - - * - - *
                     |
beta:                *

En caso de que una regresión se encuentre las cosas apuntan a nuestro favor, pues la edición beta primero fue probada antes de enviar los cambios a la versión estable, lo que se hace en estos casos es aplicar un parche en la rama master y después migrarlo a la rama beta.

nightly: * - - * - - * - - * - - * - - *
                     |
beta:                * - - - - - - - - *

Seis semanas después de la liberación de la rama beta es tiempo de enviar una nueva versión estable, por lo que una rama llamada stable saldrá de la rama beta:

nightly: * - - * - - * - - * - - * - - * - * - *
                     |
beta:                * - - - - - - - - *
                                       |
stable:                                *

Bien, una nueva versión de Rust está lista para usarse, pero tenemos que considear algo y es que han pasado 6 semanas, por lo que una nueva versión beta viene en camino, por lo tanto cada que se libera una versión estable, se crea una nueva versión beta.

Herramientas de desarrollo para Rust

  • Racer (Nightly): cargo install racer.
  • rustfmt (Stable - Nightly): rustup component add rustfmt.
  • rust-doc (Stable - Nightly): rustup component add rust-doc.

Si deseamos una integración propia con un IDE debemos de instalar rls el cual es un servidor de lenguaje que nos ayudará con el resaltado de errores en tiempo real y nos proporcionará de otras funciones útiles.

  • RLS (Stable - Nightly): rustup component add rls-preview rust-analysis rust-src

¡Listo! Con esto tenemos nuestro entorno base para escribir programas en Rust. Ahora tenemos que elegir un IDE para empezar a desarrollar.

Ve al capítulo 2.4 para ver nuestras recomendaciones o al capítulo 3 si deseas comenzar a escribir tus programas en Rust.

Instalación en Mac OS

La instalación en Mac OS es similar a la instalación en los sistemas operativos tipo unix.

Antes de empezar, si posees el gestor de paquetes homebrew te recomendamos hacer la instalación por este medio ya que es más sencillo y el resultado es el mismo:

  • Instalación de Rustup $ brew install rustup

  • Iniciar la instalación de Rust $ rustup-init

  • Verificar nuestra instalación de Rust con: $ rustc --version

Puedes instalar desde la terminal provista por tu sistema operativo ejecutando el siguiente comando:

curl https://sh.rustup.rs -sSf | sh

Con esto descargaremos la versión más reciente de Rustup y procederemos con la instalación del lenguaje.

No te preocupes si resulta confuso al inicio, el instalador de Rust te guiará paso a paso en el proceso.

Si te consideras un novato en el lenguaje te recomendamos mantener los ajustes de instalación por defecto.

Para actualizar tus herramientas de Rust necesitaras ejecutar el comando $ rustup update.

Configurar la variable de entorno

Al proceder con la instalación de Rust, todas las herramientas se almacenarán en el directorio ~/.cargo/bin, ahí encontrarás todo el software que has descargado como rustc, cargo y rustup.

Es opcional (y conveniente) incluir este directorio en una variable de entorno, durante la instalación rustup intentará configurar dicha variable definida como PATH. Como todas las líneas de comandos son diferentes las modificaciones hacia PATH podrían no surtir efecto hasta que se reinicie la consola, al salir de la sesión o puede no funcionar del todo, por lo que como usuario te tocará corregir este error por tus medios.

Si deseas empaparte con un poco más de información continúa leyendo o si consideras que la instalación es suficiente puedes pasar al siguiente capítulo.

Los canales de actualización

El desarrollo de Rust es muy activo, por lo que opera en tres canales de distribución:

  • Stable
  • Beta
  • Nightly

Si eres un usuario novel te recomendamos mantenerte en el canal Stable.

Los canales Beta o Nightly son para aquellos valientes que desean probar características más recientes del lenguaje aunque a veces son necesarios para algunas herramientas.

Vamos a explicar/traducir el proceso de liberación de Rust como viene explicado en el libro:

Necesitarás conocimientos básicos de Git para entender algunas cosas.

Cada vez que se añade una característica a Rust, se crea un commit en la rama master del repositorio. Esto pasa con frecuencia ya que la comunidad de Rust es muy activa, por lo tanto cada noche una nueva versión del canal Nightly se produce, es decir, todos los días se libera una nueva versión con el hash del último commit aceptado dentro de Nightly, la rama master durante el transcurso del día podría verse algo así:

nightly: * - - * - - *

Cada * representa un commit.

Como los ciclos de liberación son fijos cada seis semanas el equipo de desarrollo de Rust se prepara para liberar una nueva versión, antes que nada primero deben migrar los cambios, por lo que la rama beta sale de la rama master y con eso tendremos nuestra liberación beta.

nightly: * - - * - - *
                     |
beta:                *

La mayoría de los usuarios de Rust no utiliza este canal de forma activa, en su lugar utilizan Sistemas de Integración Continua para detectar cualquier posible regresión o error. Mientras esto ocurre, la rama master continúa actualizandose.

nightly: * - - * - - * - - * - - *
                     |
beta:                *

En caso de que una regresión se encuentre las cosas apuntan a nuestro favor, pues la edición beta primero fue probada antes de enviar los cambios a la versión estable, lo que se hace en estos casos es aplicar un parche en la rama master y después migrarlo a la rama beta.

nightly: * - - * - - * - - * - - * - - *
                     |
beta:                * - - - - - - - - *

Seis semanas después de la liberación de la rama beta es tiempo de enviar una nueva versión estable, por lo que una rama llamada stable saldrá de la rama beta:

nightly: * - - * - - * - - * - - * - - * - * - *
                     |
beta:                * - - - - - - - - *
                                       |
stable:                                *

Bien, una nueva versión de Rust está lista para usarse, pero tenemos que considear algo y es que han pasado 6 semanas, por lo que una nueva versión beta viene en camino, por lo tanto cada que se libera una versión estable, se crea una nueva versión beta.

Herramientas de desarrollo para Rust

  • Racer (Nightly): cargo install racer.
  • rustfmt (Stable - Nightly): rustup component add rustfmt.
  • rust-doc (Stable - Nightly): rustup component add rust-doc.

Si deseamos una integración propia con un IDE debemos de instalar rls el cual es un servidor de lenguaje que nos ayudará con el resaltado de errores en tiempo real y nos proporcionará de otras funciones útiles.

  • RLS (Stable - Nightly): rustup component add rls-preview rust-analysis rust-src

¡Listo! Con esto tenemos nuestro entorno base para escribir programas en Rust. Ahora tenemos que elegir un IDE para empezar a desarrollar.

Ve al capítulo 2.4 para ver nuestras recomendaciones o al capítulo 3 si deseas comenzar a escribir tus programas en Rust.

Instalación en Gnu/Linux

La instalación en Gnu/Linux es la instalación más utilizada por los programadores del lenguaje Rust.

Antes de empezar, toma un aviso de nosotros, muchas distribuciones de GNU/Linux ya poseen Rust y sus herramientas en los repositorios oficiales, si bien esto lleva a una instalación rápida las versiones de Rust que ofrecen pueden no estar en su versión más actual, excluyendo al usuario de la mayor parte de características nuevas que las actualizaciones pueden ofrecer.

Puedes instalar desde la terminal provista por tu sistema operativo ejecutando el siguiente comando:

curl https://sh.rustup.rs -sSf | sh

Con esto descargaremos la versión más reciente de Rustup y procederemos con la instalación del lenguaje.

No te preocupes si resulta confuso al inicio, el instalador de Rust te guiará paso a paso en el proceso.

Si te consideras un novato en el lenguaje te recomendamos mantener los ajustes de instalación por defecto.

Para actualizar tus herramientas de Rust necesitaras ejecutar el comando $ rustup update.

Configurar la variable de entorno

Al proceder con la instalación de Rust, todas las herramientas se almacenarán en el directorio ~/.cargo/bin, ahí encontrarás todo el software que has descargado como rustc, cargo y rustup.

Es opcional (y conveniente) incluir este directorio en una variable de entorno, durante la instalación rustup intentará configurar dicha variable definida como PATH. Como todas las líneas de comandos son diferentes las modificaciones hacia PATH podrían no surtir efecto hasta que se reinicie la consola, al salir de la sesión o puede no funcionar del todo, por lo que como usuario te tocará corregir este error por tus medios.

Si no funciona la modificación de la variable PATH en el archivo ~/.profile puedes pegar la siguiente línea en tu archivo .bashrc (o cualquier archivo de configuración de la shell que utilices).

export PATH="$HOME/.cargo/bin:$PATH"

Si deseas empaparte con un poco más de información continúa leyendo o si consideras que la instalación es suficiente puedes pasar al siguiente capítulo.

Los canales de actualización

El desarrollo de Rust es muy activo, por lo que opera en tres canales de distribución:

  • Stable
  • Beta
  • Nightly

Si eres un usuario novel te recomendamos mantenerte en el canal Stable.

Los canales Beta o Nightly son para aquellos valientes que desean probar características más recientes del lenguaje aunque a veces son necesarios para algunas herramientas.

Vamos a explicar/traducir el proceso de liberación de Rust como viene explicado en el libro:

Necesitarás conocimientos básicos de Git para entender algunas cosas.

Cada vez que se añade una característica a Rust, se crea un commit en la rama master del repositorio. Esto pasa con frecuencia ya que la comunidad de Rust es muy activa, por lo tanto cada noche una nueva versión del canal Nightly se produce, es decir, todos los días se libera una nueva versión con el hash del último commit aceptado dentro de Nightly, la rama master durante el transcurso del día podría verse algo así:

nightly: * - - * - - *

Cada * representa un commit.

Como los ciclos de liberación son fijos cada seis semanas el equipo de desarrollo de Rust se prepara para liberar una nueva versión, antes que nada primero deben migrar los cambios, por lo que la rama beta sale de la rama master y con eso tendremos nuestra liberación beta.

nightly: * - - * - - *
                     |
beta:                *

La mayoría de los usuarios de Rust no utiliza este canal de forma activa, en su lugar utilizan Sistemas de Integración Continua para detectar cualquier posible regresión o error. Mientras esto ocurre, la rama master continúa actualizandose.

nightly: * - - * - - * - - * - - *
                     |
beta:                *

En caso de que una regresión se encuentre las cosas apuntan a nuestro favor, pues la edición beta primero fue probada antes de enviar los cambios a la versión estable, lo que se hace en estos casos es aplicar un parche en la rama master y después migrarlo a la rama beta.

nightly: * - - * - - * - - * - - * - - *
                     |
beta:                * - - - - - - - - *

Seis semanas después de la liberación de la rama beta es tiempo de enviar una nueva versión estable, por lo que una rama llamada stable saldrá de la rama beta:

nightly: * - - * - - * - - * - - * - - * - * - *
                     |
beta:                * - - - - - - - - *
                                       |
stable:                                *

Bien, una nueva versión de Rust está lista para usarse, pero tenemos que considear algo y es que han pasado 6 semanas, por lo que una nueva versión beta viene en camino, por lo tanto cada que se libera una versión estable, se crea una nueva versión beta.

Herramientas de desarrollo para Rust

  • Racer (Nightly): cargo install racer.
  • rustfmt (Stable - Nightly): rustup component add rustfmt.
  • rust-doc (Stable - Nightly): rustup component add rust-doc.

Si deseamos una integración propia con un IDE debemos de instalar rls el cual es un servidor de lenguaje que nos ayudará con el resaltado de errores en tiempo real y nos proporcionará de otras funciones útiles.

  • RLS (Stable - Nightly): rustup component add rls-preview rust-analysis rust-src

¡Listo! Con esto tenemos nuestro entorno base para escribir programas en Rust. Ahora tenemos que elegir un IDE para empezar a desarrollar.

Ve al capítulo 2.4 para ver nuestras recomendaciones o al capítulo 3 si deseas comenzar a escribir tus programas en Rust.

¡Hora de elegir un editor!

Bien, empecemos con las malas noticias: Rust no tiene un IDE oficial, de hecho no existen IDEs 100% funcionales que estén dedicados enteramente a Rust, por lo que necesitarás elegir entre los editores de texto que rondan por la comunidad o si ya utilizas uno necesitarás descargar los plugins necesarios.

Todos los datos de esta página fueron extraidos de la página ARE WE IDE YET?. Nosotros solo simplificaremos lo establecido ahí.

Se indicarán los requerimientos entre paréntesis.

ATOM

Atom es un editor de texto desarrollado por GitHub utilizando la biblioteca Electron, es extensible y fácil de utilizar.

Eficiencia de atom en Rust:

  • Resaltado de sintaxis (Plugin)
  • Snippets (Plugin)
  • Autocompletado (Plugin)
  • Linternas (Plugin)
  • Formato de código (Plugin)
  • Ir a la definición (Plugin)
  • Depuración
  • Tooltips de documentación (Plugin)

Plugins de ATOM para Rust


Emacs

Emacs es un editor de texto extensible, personalizable y libre, escrito en Lisp.

Eficiencia de emacs en Rust:

  • Resaltado de sintaxis (Plugin)
  • Snippets (Plugin)
  • Autocompletado (Plugin + Racer)
  • Linternas (Plugin)
  • Formato de código (Plugin)
  • Ir a la definición (Plugin + Racer)
  • Depuración
  • Tooltips de documentación (Plugin + Racer)

Plugins de Emacs para Rust


Sublime text 2/3

Sublime text es un editor de texto escrito en C++, extensible y poderoso para editar código fuente.

Eficiencia de sublime text en Rust:

  • Resaltado de sintaxis
  • Snippets
  • Autocompletado (Plugin + Racer)
  • Linternas
  • Formato de código (Plugin)
  • Ir a la definición (Plugin + Racer)
  • Depuración
  • Tooltips de documentación

Plugins de Sublime Text para Rust


Vim/Neovim

Vim es un editor de texto extensible, altamente personalizable y útil para casi cualquier propósito, se incluye como reemplazo de vi en la mayoría de los sistemas operativos tipo UNIX.

Eficiencia de Vim/Neovim en Rust:

  • Resaltado de sintaxis (Plugin)
  • Snippets (Plugin)
  • Autocompletado (Plugin + Racer)
  • Linternas (Plugin + Racer)
  • Formato de código (Plugin)
  • Ir a la definición (Plugin + Racer)
  • Depuración
  • Tooltips de documentación (Plugin + Racer)

Plugins de Vim/Neovim para Rust


VSCode / Visual Studio Code / VSCodium

  • VSCode es una herramienta que combina la simplicidad de un editor de texto con las necesidades de los desarrolladores. (VSCode es el proyecto padre de Visual Studio Code y VSCodium).

  • Visual Studio Code es un editor derivado de VSCode el cual es clonado por Microsoft y modificado con telemetría, llaves de API cerradas y herramientas de integración avanzada.

  • VSCodium es un derivado de VSCode el cual es una compilación del mismo que provee un editor 100 FLOSS (Free, Libre and Open Source Software). Por lo que este no contiene telemetría o rastro alguno de la marca de Microsoft, ideal para los entusiastas del software libre.

Eficiencia de VSCode en Rust:

  • Resaltado de sintaxis (Plugin)
  • Snippets (Plugin)
  • Autocompletado (Plugin + Racer)
  • Linternas (Plugin)
  • Formato de código (Plugin)
  • Ir a la definición (Plugin + Racer)
  • Depuración (Plugin)
  • Tooltips de documentación (Plugin + Racer)

Plugins de VSCode para Rust


Eclipse

Eclipse es un Entorno de Desarrollo Integrado (IDE) escrito en Java el cual está compuesto por un conjunto de herramientas que le garantizan extensibilidad y poder para el desarrollo multiplataforma.

Eficiencia de Eclipse en Rust:

  • Resaltado de sintaxis (Plugin)
  • Snippets (Plugin)
  • Autocompletado (Plugin)
  • Linternas (Plugin)
  • Formato de código (Plugin)
  • Ir a la definición (Plugin)
  • Depuración (Plugin)
  • Tooltips de documentación (Plugin)

Plugins de Eclipse para Rust


IntelliJ IDEA

IntelliJ IDEA es un IDE desarrollado por la compañía JetBrains hecha en Kotlin, Java y Python, cuenta con las ediciones de pago y comunitaria.

Eficiencia de IntelliJ en Rust:

  • Resaltado de sintaxis (Plugin)
  • Snippets (Plugin)
  • Autocompletado (Plugin)
  • Linternas (Plugin)
  • Formato de código (Plugin)
  • Ir a la definición (Plugin)
  • Depuración (Plugin)
  • Tooltips de documentación (Plugin)

Plugins de IntelliJ para Rust


Visual Studio

Visual Studio es un IDE disponible para las plataformas de Microsoft Windows y Mac OS el cual posee todas las características para desarrollar software en Android, iOS, Windows, Web y Cloud Computing.

Eficiencia de Visual Studio en Rust:

  • Resaltado de sintaxis
  • Snippets
  • Autocompletado
  • Linternas
  • Formato de código
  • Ir a la definición (Plugin)
  • Depuración (Plugin)
  • Tooltips de documentación

Plugins de Visual Studio para Rust


GNOME Builder

GNOME Builder es un IDE desarrollado en C para la plataforma Gnu/Linux el cual cuenta con búsqueda global, autocompletado, mini-mapa, documentación y edición avanzada.

Eficiencia de Builder en Rust:

  • Resaltado de sintaxis
  • Snippets
  • Autocompletado
  • Linternas
  • Formato de código
  • Ir a la definición
  • Depuración
  • Tooltips de documentación

Otros editores que soportan Rust:

  • BBEdit
  • Midnight Commander
  • Geany
  • gedit
  • Kate
  • Textadept
  • Ride
  • Solid Oak

¡Hola Rust!

Tenemos todo lo necesario, ahora vamos a escribir nuestro primer programa en Rust.

Existe una tradición entre los programadores, siempre que se aprende un nuevo lenguaje de programación, el primer programa que se escribe es un "Hola mundo".

No cubriremos a fondo el uso de la línea de comandos por lo tanto asumiremos que ya posees las habilidades para crear, renombrar o borrar directorios/archivos.

Vamos a crear nuestro primer archivo fuente de Rust y lo llamaremos main.rs, es importante saber que TODOS los archivos de Rust terminan con la extensión .rs, las reglas para el nombre de los archivos son las mismas que aplican para otros lenguajes de programación.

Ahora con tu editor de texto favorito abre el archivo main.rs y coloca lo siguiente:

fn main() {
    println!("¡Hola Mundo!");
}

Es un pequeño programa que imprime las palabras ¡Hola Mundo! en la consola.

Puedes ejecutar el código desde este mismo libro aun así, te recomendamos que practiques en tu terminal.

Guarda tu archivo main.rs y en tu terminal procede a llamar al compilador de Rust llamado rustc. Mas adelante explicaremos como funciona a fondo rustc, por ahora procederemos a compilar nuestro programa de la siguiente manera:

$ rustc main.rs
$ ./main
¡Hola Mundo!

Los comandos están expresados en un entorno UNIX-Like.

Vamos a descomponer nuestro programa en partes para entender un poco mejor lo que está pasando.

Veamos la primera parte del programa:

fn main() {

Lo primero que vemos es el abstracto fn el cual se utiliza para declarar funciones en Rust. Mas delante podemos ver main(), esto es el identificador de la función, a la derecha podemos ver un par de paréntesis, al igual que en otros lenguajes los paréntesis al lado del identificador de la función sirven para indicar los parámetros que esta va a recibir al momento de ser llamada.

El último elemento que podemos ver es una "llave abierta", ésta indica el inicio de un bloque de código {.

La siguiente línea que podemos ver es esta:

println!("¡Hola Mundo!");

A diferencia de otros lenguajes, Rust no utiliza funciones para la salida de consola, en este caso println! es un macro que es un elemento de metaprogramación que exploraremos más tarde, por ahora recuerda que al llamar un macro siempre deberás de colocar un ! después del identificador.

Dentro del macro println! encontramos el elemento "¡Hola Mundo!". Esto es una cadena de carácteres que funciona como argumento del macro.

En la última línea podemos ver una llave cerrada, la cual indica el final de un bloque de código.

Rust es un lenguaje de programación compilado, si tienes experiencia con lenguajes como C o C++ sabrás que después de escribir el código fuente es necesario pasar el archivo resultante por un compilador, en el caso de C o C++ se utiliza gcc o clang, en Rust usaremos rustc.

Si vienes de lenguajes dinámicos, mejor conocidos como interpretados como Python o Ruby probablemente te sea un poco difícil acostumbrarte a compilar y ejecutar. A diferencia de otros lenguajes de programación compilados Rust puede considerarse como adelantado en esa cuestión ya que puedes compilar un programa y enviar el binario generado a otra persona para que lo ejecute, incluso sin tener Rust instalado.

Cuando proporcionas a otra persona tu script con terminación en .rb o .py todo lo que necesitan es tener instalado en su computadora el lenguaje de programación correspondiente.

Compilar nuestros programas con rustc está bien si estamos desarrollando software simple, pero si deseamos crear proyectos más ambiciosos y con un poco más de complejidad, en el capítulo 4 discutiremos acerca de cargo, el gestor de paquetes de Rust.

Cargo ¿run?

En el capítulo anterior creamos nuestro primer programa en Rust, un simple "Hola mundo".

Pero pensemos un momento: ¿Y si deseamos crear un proyecto más grande?, ¿Qué tal si necesitamos crear una herramienta de línea de comandos más compleja? o quizá tenemos una gran idea para crear un API para usarse en Inteligencia Artificial.

De una forma u otra necesitaremos una forma de manejar nuestro proyecto de manera eficiente, aquí entra cargo el gestor de paquetes de Rust.

Cargo no solo se limita a ser un gestor de paquetes, también es un sistema de construcción y un excelente manejador de dependencias. Muchos programadores de Rust, a los cuales llamaremos Rustáceos en adelante (Derivado de la palabra "Crustáceos") utilizan cargo para manejar sus proyectos ya que éste realiza muchas acciones por nosotros, descarga y compila las bibliotecas que son dependencias de nuestro código, le da formato a nuestro código si somos inexpertos en el tema, ejecuta pruebas y despliega nuestro código listo para enviarse a producción.

Casi todos (por no decir la palabra "Todos") los proyectos de Rust utilizan Cargo, si has instalado Rust utilizando el instalador oficial (rustup) entonces ya posees Cargo instalado y listo para usarse.

Primer proyecto con Cargo

Para crear un nuevo proyecto utilizando Cargo debemos ejecutar el siguiente comando:

$ cargo new --bin hola_cargo

Esto creará un nuevo proyecto de Cargo, si entramos en el directorio creado nos daremos cuenta que dentro hay varios archivos, un directorio y que se ha inicializado un nuevo repositorio con la herramienta git.

Vamos a editar el archivo más llamativo del directorio llamado Cargo.toml:

[package]
name = "hola_cargo"
version = "0.1.0"
authors = ["nombre <nombre@ejemplo.com>"]
edition = "2018"

[dependencies]

La primera línea del archivo es la sección [package] que indicará todos los detalles al momento de configurar un paquete de Cargo.

Las siguientes líneas contienen información necesaria para poder construir y compilar el paquete en cuestión:

  • Nombre del paquete o crate.
  • Versión del paquete
  • Autor o autores del paquete
  • La edición de Rust (Hablaremos más adelante de eso).

La siguiente sección se llama [dependencies], debajo de esta se colocarán todas las dependencias requeridas para construir nuestro paquete de Rust, las usaremos más adelante.

Como mencionamos más arriba, cargo genera un directorio de nombre src en el cual se incluye un archivo llamado main.rs, este archivo en cuestión contiene un "Hello World" dentro.

Cargo asume que TODOS tus archivos de código fuente se encontrarán dentro del directorio src/ ya que el directorio raíz del proyecto solo estará dedicado a información acerca del mismo, véase archivos README, LICENSE o las configuraciones escritas en TOML.

Ejecutar proyectos utilizando cargo

Si deseamos construir un proyecto utilizando Cargo solo es necesario escribir en nuestra terminal (dentro del directorio de nuestro proyecto):

$ cargo build

La saluda de la terminal nos debería mostrar una salida indicandonos si nuestro proyecto se pudo construir o si falló en algún punto:

   Compiling hola_cargo v0.1.0 (/home/FutureLab/Escritorio/hola_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.39s

Cuando le damos la instrucción build a cargo éste creará un binario ejecutable en un nuevo árbol de directorios, específicamente dentro de target/debug/<archivo binario>.

Además de compilar un binario ejecutable Cargo también descargará y compilará las dependencias necesarias para nuestro proyecto, al mismo tiempo creará un archivo nuevo llamado Cargo.lock, no te alarmes, este archivo vigilará las versiones de tus dependencias.

Si bien podríamos ejecutar los binarios desde su ruta con $ ./target/debug/hola_cargo esto es ineficiente, por lo que cargo tiene otra función para compilar y ejecutar nuestros proyectos en un solo comando:

$ cargo run

Si ejecutamos esta orden, Cargo buscará los archivos .rs dentro de nuestro directorio src/, los compilará e inmediatamente después los ejecutará si no encontró problema alguno.

    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/hola_cargo`
Hello, world!

Cargo posee una variedad de comandos entre ellos:

  • check => Se encarga de revisar que el código compile sin producir ejecutables.
  • clean => Elimina el directorio target/.
  • doc => Construye el paquete y sus dependencias con documentación.
  • init => Crea un nuevo proyecto en un directorio existente.
  • test => Ejecuta las pruebas.
  • bench => Ejecuta puntos de referencia.
  • update => Actualiza las dependencias de Cargo.lock.
  • search => Busca crates en el registro.
  • publish => Publica el paquete actual al registro.
  • install => Instala un binario de Rust en $HOME/.cargo/bin.
  • uninstall => Desinstala un binario de Rust.

La ventaja de Cargo es que los comandos que se pueden ejecutar son independientes de cualquier plataforma por lo que funciona de la misma manera en Windows, MacOS y Gnu/Linux.

Liberar un paquete

Cuando hayas terminado tu proyecto solo necesitarás la bandera --release para generar un binario optimizado, esto generará un binario ejecutable en el directorio target/release.

Fin de la lección

Por ahora has aprendido a utilizar Cargo y a crear un pequeño hola mundo en Rust, pero imprimir mensajes de ese tipo en la consola no es divertido por lo que en el siguiente capítulo crearemos un programa llamado "FizzBuzz" el cual es una pregunta utilizada en las entrevistas de programación.

¡Prepárate para comenzar a utilizar Cargo de verdad!

Creando un programa FizzRust...FizzBuzz.

⚠️ LECTURA PROLONGADA ⚠️

Hemos aprendo a las bases para utilizar nuestras herramientas de Rust y creamos nuestro primer "Hola Mundo" en poco tiempo, pero ahora pasemos a crear un programa más interesante, un programa llamado "FizzBuzz".

¿Fizz..que?

FizzBuzz es un juego que se utiliza con los niños para mejorar su capacidad de aplicar una división de manera mental. No, no planeamos tratarte como un niño pues esta prueba también se utiliza en las entrevistas de programación y funciona como un filtro, normalmente se les pide lo siguiente a los candidatos:

"Escriba un programa que imprima los números desde 1 hasta 100. Pero en cada número que sea múltiplo de 3 se deberá imprimir "Fizz" en el lugar del número, el mismo caso para los números que sean múltiplos de 5. Por cada número que sea múltiplo de 3 y 5 se deberá imprimir FizzBuzz"

Por más simple que parezca la prueba, muchos programadores no logran pasarla pues no es un patrón que se vea dentro de las enseñanzas clásicas y por que no es posible representar las pruebas de manera directa y simple sin necesidad de duplicar algo.

Aun así no nos vamos a adentrar en la complejidad de la prueba y explicar los árboles de desiciones en este capítulo sería desviarnos del objetivo principal, existen diferentes formas de resolver un problema FizzBuzz en diferentes lenguajes, aquí puedes ver algunos ejemplos.

Python

def fizzbuzz(x):
    """Simple FizzBuzz, courtesy of @RodolfoFerro on @GitHub"""

    if x % 3 == 0 and x % 5 == 0:
        return "FizzBuzz"
    elif x % 3 == 0:
        return "Fizz"
    elif x % 5 == 0:
        return "Buzz"
    else:
        return str(x)

if __name__ == '__main__':
    sequence = '\n'.join(fizzbuzz(x) for x in range(1, 100))
    print(sequence)

C (ANSI + Kernel Coding Style)

#include <stdio.h>

int main(int argc, char *argv[])
{
        for (int i = 1; i <= 100; i++) {
                if (i % 3 == 0)
                        printf("Fizz");
                if (i % 5 == 0)
                        printf("Buzz");
                if (i % 3 != 0 && i % 5 != 0)
                         printf("%d", i);

                printf("\n");
        }
        return 0;
}

El problema con este ejemplo es que no se ve un caso para el "FizzBuzz". Nótese que no existe la impresión de una nueva línea en el cuarto printf. Si el número es un múltiplo de 3 y 5 las primeras dos condiciones se cumplen, por lo tanto ambos casos se ejecutan.

Si deseas agregar un ejemplo de FizzBuzz al libro eres bienvenido, solo abre un Pull Request que incluya el programa con tu lenguaje de programación favorito :D

Bien, ahora vamos a tomar la aproximación de Rust. En este proyecto crearemos el mismo programa pero con salida de colores y en el camino explicaremos por encima algunos conceptos base de programación en Rust.

Preparando el proyecto

Utilizando nuestros conocimientos previos lo primero que haremos será crear un nuevo proyecto utilizando Cargo, vamos a llamarlo FizzBuzz.

$ cargo new --bin fizzbuzz

Ahora entremos en el directorio creado por Cargo:

$ cd fizzbuzz

Vamos a editar el archivo Cargo.toml el cual se encuentra por defecto, en nuestro caso los programadores de Future Lab decidieron dejarlo de esta manera:

[package]
name = "fizzbuzz"
version = "0.1.0"
authors = ["Future Lab <mxfuturelab@futuremail.com>"]
edition = "2018"

[dependencies]

En la parte superior mencionamos que nuestro programa tendría una salida a terminal de colores, para esto necesitamos agregar un crate a nuestra sección [dependencies]. La crate que utilizaremos es colored un paquete de Rust que nos permite imprimir texto con decoraciones en la terminal.

Nuestro archivo Cargo.toml debería quedar así:

[package]
name = "fizzbuzz"
version = "0.1.0"
authors = ["Future Lab <mxfuturelab@futuremail.com>"]
edition = "2018"

[dependencies]
colored = "1.6"

Bien, tenemos las dependencias que necesitamos para nuestro programa en Rust, digámosle a Cargo que las descargue y las compile para poder utilizarlas en nuestro proyecto sin problema alguno con:

$ cargo build

Esto debería de descargar y compilar colored y dejarlo listo para usar:

   Updating crates.io index
   Compiling lazy_static v1.2.0
   Compiling colored v1.6.1
   Compiling fizzbuzz v0.1.0 (/home/futurelab/Escritorio/fizzbuzz)
    Finished dev [unoptimized + debuginfo] target(s) in 13.38s

Escribir una base

Utilizando el editor de tu preferencia abre el archivo main.rs, este es el archivo que vamos a modificar, elimina la línea que contiene el mensaje de impresión (println!) y procede a escribir el siguiente código, no te preocupes si no lo entiendes pues lo explicaremos a lo largo de este capítulo.

fn main() {
    for x in 0..{
        match (x % 3, x % 5) {
            (0, 0) => println!("FizzBuzz"),
            (0, _) => println!("Fizz"),
            (_, 0) => println!("Buzz"),
            (_, _) => println!("{}", x)
        }
    }
}

No ejecutes este código aún, es una versión de pruebas que modificaremos a lo largo de este y los siguientes capítulos.

Comprendiendo el código

¿Que está pasando aquí? Hay muchos elementos nuevos (Claro, todo es nuevo a diferencia del macro println! que vimos en el capítulo pasado) por lo que vamos a volver a descomponer línea por línea todo el programa.

Revisemos dentro de la función main, esta función es la misma que utilizamos en nuestro primer hola mundo por lo que no hay necesidad de explicarla así que nos dirigiremos a la segunda línea de nuestro código actual:

    for x in 0..{

El iterador

Como mencionamos en el capítulo 2, asumiremos que posees conocimientos básicos de programación por lo que debe ser evidente que esto es algo conocido como "ciclo for", los exploraremos más adelante en el capítulo de control de flujo, por ahora vamos a dejar claras las bases de un ciclo for en Rust.

Lo primero que podemos observar es que la sintaxis de los ciclos for no es similar a la utilizada en lenguajes como C, JavaScript o Java:

for (x = 0; x < 10; x++) {
        printf("%i\n", x);
}

En su lugar (y en términos más abstractos) los ciclos for en Rust se ven algo así:

for x in 0..5 {
    println!("{}", x);
}

Si abstraemos los términos podríamos describirlos así:

for variable in expresion {
    código
}

Siendo "expresion" un iterador. En nuestro ejemplo elegimos el rango de 0..5, esta expresión consta de un inicio y un fin y el ciclo realizará una iteración entre esos valores, aunque Rust posee rangos inclusivos, por defecto el límite superior es exclusivo, por lo tanto nuestro ciclo for imprimirá los valores del 0 al 4, no hasta el número 5.

La razón por la que Rust no posee ciclos for con una sintaxis parecida a C es sencilla, al tener esa sintaxis se controla manualmente cada elemento del ciclo lo cual deja el código susceptible a errores humanos.

Pero hay algo diferente en nuestro ciclo for, si volvemos por un momento a nuestro código podemos notar que no tenemos un valor definido como límite superior del ciclo:

    for x in 0..{

En su lugar tenemos una llave abierta, indicando el inicio de las instrucciones del ciclo. Esto es muy sencillo, cuando Rust encuentre un ciclo for de este tipo lo ejecutará infinitamente.

Nos hemos equivocado a propósito, pues Rust posee una forma más sencilla de realizar ciclos infinitos.

Por ahora continuaremos explorando la estructura del ciclo for:

        match (x % 3, x % 5) {
            (0, 0) => println!("FizzBuzz"),
            (0, _) => println!("Fizz"),
            (_, 0) => println!("Buzz"),
            (_, _) => println!("{}", x)

Múltiples casos, múltiples resultados.

Aquí podemos ver otro elemento "antes de tiempo" que viene del control de flujo en Rust, en este caso match.

match es el equivalente a switch en otros lenguajes de programación como C o C++, una alternativa a comparar y ejecutar los diferentes valores que puede tomar una variable.

La estructura de la palabra clave match puede ser utilizada de formas complejas y aunque no explicaremos a fondo su uso por ahora, intentaremos explicarte como funciona match en el caso de nuestro código.

Para que match funcione correctamente necesita una expresión para evaluar, como nosotros tenemos x como variable (declarada en el alcance del ciclo for) y ésta se encuentra en uso como iterador su valor mutará en cada "vuelta" del ciclo, en este caso x aumentará su valor en una unidad por iteración por lo que x será lo que evaluaremos.

Dentro de los paréntesis tenemos dos operaciones que procesarán x y arrojarán un resultado que será enviado a cualquiera de los posibles casos dentro de match, en este caso nuestras dos operaciones son las siguientes: x % 3 y x % 5.

El operador % cumple la misma función que en otros lenguajes, retorna el residuo de la división entre dos números, sabiendo esto cada iteración comparará a x dos veces, regresando el residuo del valor de x dividido entre 3 y 5, dependiendo del resultado se enviará a la pantalla el mensaje.

Veamos la primera condición:

            (0, 0) => println!("FizzBuzz"),

Si el residuo resultante de la división de x/3 Y x/5 es igual a cero entonces se enviará a la pantalla el mensaje "FizzBuzz".


En la segunda condición las cosas cambian un poco, podemos observar un elemento nuevo, un guión bajo (_), éste funciona de la misma manera que un default: funciona dentro de un switch.

En este caso _ funciona como un "atrapa-todo" en el cual caerán todos los resultados que no coincidan don las condiciones expresadas en los casos de match. Si observamos detenidamente el código podemos llegar a la conclusión de que _ funcionará en caso de que la división de x/3 ó x/5 arrojen cualquier valor diferente de 0

            (0, _) => println!("Fizz"),
            (_, 0) => println!("Buzz"),
            (_, _) => println!("{}", x)

Agregando algo de color

Bien, nuestro programa FizzBuzz funciona, en un ciclo infinito que se ejecutará hasta que nuestra computadora tenga la necesidad de detenerlo, más tarde arreglaremos ese problema, por ahora vamos a darle un poco de color a la salida del programa. Para esto utilizaremos un crate llamado colored, la misma que agregamos al inicio de este capítulo, el uso es sencillo, por ejemplo, podemos imprimir "Hola Rust" en color rojo:

extern crate colored;

use colored::*;

fn main() {
    println!("{}", "¡Hola Rust!".red());
}

Eliminamos la opción de ejecución en este ejemplo, pues el navegador no soporta la impresión de texto de color.

Hagamos una ligera modificación, cuando el programa tenga que imprimir "Fizz", lo hará en un color rojo, en caso de que necesite imprimir "Buzz" será en color amarillo y en el caso de imprimir "FizzBuzz" lo hará de color cían.

(No es necesario que pongas esos colores si no son de tu agrado, en la guía oficial del crate están listados todos los colores y estilos disponibles, anímate a experimentar un poco).

Veamos el código utilizando colores de Future Lab :D

extern crate colored;

use colored::*;

fn main() {
    for x in 0..{
        match (x % 3, x % 5) {
            (0, 0) => println!("{}","FizzBuzz".cyan()),
            (0, _) => println!("{}","Fizz".red()),
            (_, 0) => println!("{}","Buzz".yellow()),
            (_, _) => println!("{}", x)
        }
    }
}

Aun más elementos nuevos, vamos a explicarlos parte por parte:

La declaración extern crate le especifica a Rust que nuestro programa depende de un biblioteca externa a nuestro proyecto, acercándola a nuestro alcance.

extern crate colored;

La declaración use crea enlaces locales a funciones o métodos remotos, se utiliza para simplificar el uso de localización de archivos.

use colored::*;

Las siguientes líneas son sencillas de explicar:

            (0, 0) => println!("{}","FizzBuzz".cyan()),
            (0, _) => println!("{}","Fizz".red()),
            (_, 0) => println!("{}","Buzz".yellow()),
            (_, _) => println!("{}", x)

Nuestro macro println! ha cambiado, en este caso el crate colored solo funciona con cadenas de caracteres, por lo que necesitamos colocar algo llamado "placeholder" que en resumen es un espacio donde se colocará un elemento más tarde, tenemos que separar con una coma los argumentos, en ese caso el segundo argumento será nuestra cadena, en este caso "Fizz", "Buzz", y "FizzBuzz", solo resta agregar la función correspondiente. colored retorna cadenas en todas sus funciones por lo que no habrá problema si pasamos las funciones seguidas de un punto en este caso.

La impresión del programa debería verse de esta manera en una ejecución normal:

Salida De Colores

Se ve genial ¿no?, puedes probar a hacer diferentes combinaciones, por ejemplo al imprimir "FizzBuzz" hacer que cada carácter tenga un color distinto:

Salida De Colores

¡Genial! Nuestro programa ahora imprime las cosas de una manera más "elegante". Pero podemos notar un problema en las imágenes, los números evaluados son muy altos, no deberíamos de cargar al sistema con esa clase de operaciones.

Podríamos colocar un límite superior en el ciclo for en nuestro código, pero, si bien es una buena solución la verdad sea dicha, tenemos planeado enseñarte algo que causa muchos problemas con los principiantes en el lenguaje de programación Rust.

Operaciones de entrada

Entre los usuarios Novel, pedir entrada de datos al usuario es un tema común, pues no existe una manera sencilla de hacerlo como en otros lenguajes como C, Python o Ruby.

Esto tiene una razón sencilla, una entrada errónea del usuario puede causar comportamientos inesperados en los programas que podamos crear, puede parecer algo tedioso al inicio y es algo que se ha estado trabajando desde las versiones mas nuevas de Rust, aun así, las comparaciones entre Rust y otros lenguajes como Python y Ruby, carecen de sentido, pues cumplen roles diferentes.

Vamos a pedir al usuario ingresar un número entero, el cual servirá como límite superior de nuestro ciclo for, con ello el usuario tendrá el control sobre las iteraciones de nuestro programa FizzBuzz.

En este caso, si el usuario ingresa cualquier cosa que no sea un número entero se interpretará como un error irrecuperable y el programa se cerrará inmediatamente.

Primero necesitamos importar las bibliotecas necesarias para que el proyecto funcione, tendremos que crear una manera de pedir entrada al usuario y finalmente comprobar que nuestro programa funcione.

El código completo debería verse de la siguiente manera:

extern crate colored;

use colored::*;
use std::io;

fn main() {
    let mut entrada = String::new();
    println!("Ingrese el número de iteraciones deseadas:");
    io::stdin().read_line(&mut entrada).unwrap();

    let iter: i32 = entrada.trim().parse().unwrap();

    for x in 0..=iter {
        match (x % 3, x % 5) {
            (0, 0) => println!("{}", "FizzBuzz".cyan()),
            (0, _) => println!("{}", "Fizz".red()),
            (_, 0) => println!("{}", "Buzz".yellow()),
            (_, _) => println!("{}", x),
        }
    }
}

De nuevo hay muchas cosas nuevas en este código, cosa que nos beneficiará pues los temas posteriores serán mas sencillos de digerir una vez comprendamos como funcionan con este tipo de ejemplos.

Nuestro primer paso es "importar las bibliotecas necesarias".

use std::io;
//-- Mas código

Rust viene preparado con toda clase de cosas en su biblioteca estándar, sin embargo, si tuviésemos que importar cada cosa que utilizamos en nuestro código al final tendríamos un desastre. Al mismo tiempo, importar toneladas de bibliotecas a nuestro programa para dejar un gran porcentaje de éstas sin usar tampoco es algo bueno, por lo que un balance es necesario. Por lo que necesitaremos cargar las funciones de entrada y salida de la biblioteca estándar.

Una vez tengamos las bibliotecas necesarias procederemos a pedir una entrada al usuario:

//-- Recorte
    let mut entrada = String::new();
    println!("Ingrese el número de iteraciones deseadas:");
    io::stdin().read_line(&mut entrada).unwrap();
//-- Recorte

Primero necesitamos un lugar donde almacenar la entrada del usuario:

    let mut entrada = String::new();

La declaración de variables se realiza con la palabra reservada let en Rust, cubriremos eso mas tarde, por ahora todo lo que tienes que saber es que con esta línea Rust está reservando una variable mutable (mut) llamada entrada (Si vienes de un lenguaje como Java podrás notar que es un método similar al de un Scanner, solo que con el estilo de Rust).

Al igual que en otros lenguajes el operador = se utiliza para realizar una asignación, en el caso de nuestra línea de código estamos asignando el valor retornado por una función String::new, en este caso el valor que regresa la función es una nueva cadena.

Similar a C++, Rust utiliza una sintáxis de 4 puntos para las funciones asociadas, por eso al llamar ::new() estamos indicándole a Rust que new es una función asociada que retornará un String.

En resumen la línea:

    let mut entrada = String::new();

Crea una nueva variable con una instancia vacía de un String.

Ahora necesitamos indicar a nuestro usuario sus instrucciones, este es un paso importante puesto que tenemos que ser claros, como nuestros usuarios son inteligentes, asumiremos que saben lo que significa iteraciones y procederemos a imprimir un mensaje en la pantalla.

    println!("Ingrese el número de iteraciones deseadas:");

Ahora necesitamos hacer algo para que el usuario ingrese el número y procesarlo para que se almacene en nuestra variable entrada:

    io::stdin().read_line(&mut entrada).unwrap();

Como al inicio del programa utilizamos la línea use std::io; ahora tenemos las funciones y métodos de entrada de texto necesarios para trabajar, al llamar a la función stdin esta retornará una instancia de std::io::Stdin, lo que nos permitirá manejar la entrada estándar desde la terminal.

La siguiente parte del código es .read_line(&mut entrada), con ello llamamos a la función .read_line y el argumento le indica a la función que deberá guardar la entrada del usuario en una referencia para usarla mas tarde.

La última parte es la función .unwrap(), con la cual compararemos la entrada del resultado. Como indicamos al inicio de este capítulo, asumiremos que los errores son irrecuperables y unwrap() nos ayudará con ello, al llamar a ésta función estamos indicándole a Rust lo siguiente: "Si bien esto puede o no tener un valor, yo afirmo que lo tiene. En caso contrario, el programa fallará, no quiero un error recuperable".

¡Listo!, con esto podemos pedir al usuario que ingrese "algo", pero no nos basta con que ingrese "algo", necesitamos que el usuario ingrese un número y cerrar el programa si ingresa cualquier cosa que no sea considerada un número:

    let iter: i32 = entrada.trim().parse().unwrap();

A estas alturas ya sabemos lo que hace let, solo como recordatorio, estamos declarando una variable nueva, llamada iter (por iteraciones), pero hay algo nuevo aquí, específicamente : i32. ¿Qué es esto? Simple, estamos haciendo algo llamado "tipeado", en este caso estamos indicando que nuestra variable iter será tratada como un "entero de 32 bits" (No necesitamos entrar a detalle en esto, pues lo cubriremos en capítulos posteriores), después volvemos a utilizar el operador de asignación pues necesitamos que nuestra variable tenga un valor, en este caso la asignación consta de tres partes:

  • trim(): Esta función eliminará el salto de línea que el usuario ingresa al final de la función stdin, sin ésta función no podremos procesar el salto de línea y unwrap() lo detectará como un error.

  • parse(): Aquí haremos algo llamado parsing o conversión de tipos. Como podemos recordar, lo que ingresó nuestro usuario hasta ahora es una cadena, así esté conformada por números Rust por el momento piensa que es una cadena de caracteres, con esta función estamos convirtiendo esa cadena al tipo de la variable que se le está asignando, en este caso, convertimos una cadena a un entero de 32 bits.

  • unwrap() ya lo hemos cubierto, pero se asegurará de que la conversión resultante devuelva un entero de 32 bits, en caso contrario retornará un error, haciendo que el programa detenga su ejecución.

Bien, ya solo nos falta asignar el número ingresado por el usuario a nuestro ciclo for para completar nuestro programa.

Si prestaste atención notarás que el ciclo for tiene un pequeño cambio, vamos a verlo:

    for x in 0..=iter {

¡Hemos cambiado la estructura de nuestro ciclo! No es nada de que alarmarse, hemos realizado el cambio para tomar ventaja de la edición 2018 de Rust la cual nos permite utilizar ciclos inclusivos, si recordamos las reglas de los ciclos for escritas anteriormente podremos recordar lo siguiente:

"[...] por lo tanto nuestro ciclo for imprimirá los valores del 0 al 4, no hasta el número 5."

Al utilizar la notación ..= el rango será inclusivo por lo que el ciclo se repetirá el número de veces indicado, con esto evitamos realizar una operación extra sobre la entrada del usuario.

Una vez realizadas las correcciones ya podemos ejecutar nuestro programa.

¡Genial! Ahora ya sabes como realizar un programa FizzBuzz en Rust, es probable que tengas muchas preguntas en este momento ¿Por qué las variables mutan? ¿Qué es un ciclo? ¿Cuantos tipos de dato existen? ¿Cuales son los principios de Rust?

Bien, esta y tus preguntas las resolveremos en el siguiente capítulo del libro en el cual trataremos conceptos básicos de programación, si deseas el código fuente del programa lo puedes conseguir en el siguiente enlace.

Preludio

En el capítulo anterior te enseñamos a crear un pequeño programa FizzBuzz, en este pequeño capítulo comenzaremos de lleno a mostrarte las bases del lenguaje de programación Rust, también dejaremos pequeños ejercicios para que practiques los temas que tratemos en cada capítulo. También incluiremos pequeños proyectos en los que te guiaremos paso a paso para que desarrolles tu habilidad para crear las herramientas necesarias en tu entorno.

¡Vamos a por ello!

Variables y tipos

Por muy gracioso que suene, una de las primeras cosas que los programadores buscan al aprender un nuevo lenguaje es la manera que tiene de declarar variables y sus respectivos tipos, en este capítulo aprenderemos a declarar variables y a manejar diferentes tipos de datos en Rust.

Así mismo discutiremos los tipos primitivos, cuando "tipear" una variable o no, el alcance de las variables y otros tratos especiales que posee rust como la inmutabilidad.

Comentarios

En un escenario ideal el código debería auto-documentarse por medio de las buenas prácticas como los nombres descriptivos de variables, un estilo de código limpio y una estructura impecable, aun así, existen casos donde se necesita de un elemento extra para explicar o justificar la estructura de una o varias partes de nuestro programa.

Rust sigue la forma de comentar de nuestro querido lenguaje C, por lo tanto tenemos dos formas de comentar líneas de código:

  • // Comentarios con doble barra para una sola línea.
// Esto es un comentario y no se compilará
  • /* */ Comentarios del tipo bloque para múltiples líneas.
/*
Esto
es
un
comentario
largo
*/

El estilo recomendado por la guía oficial de Rust es utilizar el comentario de doble barra, incluso para varias líneas en caso de necesitar explicar tu código.

Procura utilizar el comentario multilínea solamente para comentar código.

rust-doc también ofrece comentarios para documentación utilizando tres barras ///, estos son útiles en proyectos grandes que necesitarán de algún tipo de documentación oficial además, en estos comentarios podemos utilizar sintáxis markdown para mejorar la legibilidad de nuestra documentación.

Asignación de variables

Hasta ahora hemos visto varios tipos de valores, hemos visto cadenas, números enteros, etc. Pero no debemos de confundir los valores con los objetos ni las variables.

Tendremos que dejar algo muy claro desde el principio, la asignación de variables es diferente en Rust si lo comparamos con otros lenguajes, esto es para preservar 3 carácteristicas que hacen especial al lenguaje:

  • Seguridad
  • Eficiencia
  • Concisión

A diferencia de otros lenguajes (como JavaScript o Ruby), Rust necesita un poco más de planeación al escribir código pues necesitarás dictar los tipos de los parámetros de tus funciones, de sus valores de retorno y de tus variables.

Por lo tanto Rust es un lenguaje "Estáticamente tipado" o de "Tipado estático" lo que significa que el compilador deberá conocer el tipo de los datos antes del tiempo de ejecución, este método que viene de lenguajes veteranos como C o C++ ha sido rediseñado en Rust, pues el compilador revisará que todos los caminos posibles de ejecución usarán valores solo de manera consistente con sus tipos. Esto permite que Rust detecte muchos errores de programación antes de tiempo, y es crucial para garantizar de seguridad de Rust.

Por lo tanto, en lugar de utilizar un intérprete o un compilador en tiempo real como lo harían lenguajes como Julia o LuaJIT (Lua Just In Time Compiler), Rust fue diseñado para utilizar algo llamado "Compilación anticipada" es decir una traducción completa de todo tu programa a código máquina antes de que comience a ejecutarse, por ello los tipos de datos que Rust utilizar ayudan al compilador a elegir una representación adecuada en el bajo nivel.

Cuando Rust compila el código fuente el ejecutable resultante solo contiene objetos que tengan una dirección de memoria y un valor. Dichos objetos no poseen un nombre definido, pero estos mismos objetos necesitan de un identificador en el código fuente para poder referenciarlos más tarde.

En Rust necesitaremos de la palabra reservada let para declarar cualquier variable, por ejemplo:

let edad = 20;
let nombre = "Future Lab";
let flotante = 3.1415;

Variables ¿inmutables?

Tus ojos no te están engañando, las variables en Rust son inmutables por defecto, esto se hace para preservar la seguridad en Rust, pero esto no es el fin del mundo, Rust nos ofrece la opción de mutar las variables a nuestro gusto siempre y cuando cumplamos con ciertas reglas impuestas por el compilador.

Rust no es el primer lenguaje en hacer esto, muchos lenguajes funcionales poseen esta característica. De hecho en los lenguajes 100% funcionales la mutabilidad de las variables no está permitida.

Veamos este pequeño ejemplo para ilustrar lo anterior:

Ejemplo 1.0

fn main() {
    let edad = 10;

    edad = 5;
}

El siguiente código producirá un error de compilación específicamente este:

error[E0384]: cannot assign twice to immutable variable `edad`
 --> src/main.rs:4:5
  |
2 |     let edad = 10;
  |         ---- first assignment to `edad`
3 | 
4 |     edad = 5;
  |     ^^^^^^^^ cannot assign twice to immutable variable

Rust aplica la sabiduría que muchos programadores necesitan: "Muchos errores surgen de cambios involuntarios o incorrectos de las variables, así que no permiré que el código cambie cualquier valor a menos que lo haya permitido explícitamente."

Si deseamos una variable mutable necesitaríamos indicarle a Rust específicamente que la variable es mutable, si deseamos hacer algo así necesitamos hacer lo siguiente:

Ejemplo 1.1

fn main() {
    let mut edad = 20;
    println!("Tienes {} años", edad);

    edad = 21;
    println!("Ahora tienes {} años", edad);
}

Esto debería imprimir el siguiente mensaje en pantalla:

Tienes 20 años
Ahora tienes 21 años

Para darnos una mejor idea de como funciona la mutabilidad de las variables aquí tenemos un ejemplo del código 1.0 escrito en C:

#include <stdio.h>

int main(int argc, char const *argv[])
{
        int const edad = 10;
        edad = 5;

        return 0;
}

No intentes compilarlo, no funcionará.

A comparación de las variables mutables en el ejemplo 1.1:

#include <stdio.h>

int main(int argc, char const *argv[])
{
        int edad = 20;
        //C no permite la ñ
        printf("Tienes %d anios\n", edad);

        edad = 21;
        printf("Ahora tienes %d anios\n", edad);
        return 0;
}

Contributores

Gracias a estas personas esta recopilación fué posible: [WIP]

[PERSONAS]

[ORGANIZACIONES]