Lenguajes de Programación

Por qué aprender a programar en Rust

Te contamos los motivos por los que deberías aprender Rust, el lenguaje de programación más amado por la comunidad, y cuyo futuro se presenta inmejorable.

Publicado el 01 de Marzo de 2023
Compartir

¿Eres desarrollador y quieres tener la menor cantidad de dolores de cabeza? Según las encuestas de Stack Overflow, Rust es el lenguaje de programación más amado por la comunidad. A pesar de seguir siendo un gran desconocido para muchos, cada día está creciendo lentamente, apareciendo por todos lados.

Si estás trabajando con C/C++ o JavaScript, puede ser interesante empezar a aprender Rust, ya que será un lenguaje fundamental en el futuro de la programación. ¡Sigue leyendo este contenido para conocerlo más en profundidad, saber cómo funciona y dar tus primeros pasos para probarlo!

Introducción

Rust es un lenguaje multiparadigma de alto nivel que ha tomado mucha relevancia en los últimos años y cada vez más programadores se aventuran a usarlo. Esto es en parte por tener una sintaxis similar a muchos lenguajes y, además, por ser un lenguaje con un fuerte énfasis en la velocidad, la seguridad de los accesos a la memoria y en el paralelismo. Además, tiene mucho que aportar como lenguaje en el mundo de la programación web y no solo en aplicaciones de servidor sino para poder ejecutar aplicaciones directamente en el cliente gracias a Web Assembly.

Cada una de las funcionalidades de Rust está específicamente concebida y diseñada para empoderar al programador, ya sea este último un experto en lenguajes como C++ o tenga poca experiencia en lenguajes de bajo nivel.

Historia de Rust

El lenguaje de programación Rust empezó como un experimento realizado por Graydon Hoare en su tiempo libre mientras trabajaba en Mozilla Research durante el año 2006. La idea era crear una alternativa a C y C++ más segura y concurrente, pero sin sacrificar por ello la optimización.

Así Rust fue diseñado para ser un lenguaje de bajo nivel focalizado en controlar que los programas estén libres de referencias nulas, desbordamientos de memoria y otros tipos de comportamientos imprevistos que pueden llevar a vulnerabilidades serias de seguridad.

La seguridad que provee empieza en el compilador. A diferencia de otros lenguajes como JavaScript que no tienen compilador, sino que es interpretado por los diferentes motores, Rust debe de ser compilado cada vez que se va a ejecutar. Aunque esto se pueda ver como una ralentización en la velocidad de desarrollo, lo cierto es que gracias al estricto control que hace sobre el código puede detectar muchos futuros bugs en tiempo de compilación, instando al programador a arreglarlos.

El proyecto de este nuevo lenguaje de programación fue patrocinado oficialmente por Mozilla en 2009. Más tarde en 2015 se lanzó la primera versión de Rust estable y a través de los años ha ido ganando popularidad. Tal fue así, que en la encuesta anual de Stack Overflow de desarrolladores de 2018, Rust fue votado como el lenguaje “más amado” por los desarrolladores.

Desde entonces, Rust siempre ha estado entre los lenguajes más deseados y apreciados por la comunidad.

Hoy por hoy, Rust es un lenguaje multiparadigma de alto nivel de propósito general usado en una amplia variedad de aplicaciones, incluyendo desarrollo de videojuegos, infraestructura de navegador, web assembly entre otras. Por lo que tiene mucho sentido aprender Rust.

Instalación de Rust

La mejor forma siempre de empezar a trastear con un lenguaje nuevo, es instalarlo en sí mismo o sus herramientas asociadas. Para ello, vamos a empezar por instalar la utilidad de línea de comandos rustup, que nos va a permitir manejar las versiones de Rust y sus herramientas.

Instalación en macOS y Linux

Si tu sistema operativo es macOS o Linux, es muy sencillo. Solo tienes que ejecutar el siguiente comando en una terminal y automáticamente se descargará un script y comenzará la instalación de rustup:

$ curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh

Si todo ha ido bien, deberás de ver el siguiente mensaje en tu terminal:

Rust is installed now. Great!

Si por casualidad te ha salido un error al ejecutar el comando curl puede ser que cuando se compilase libcurl en tu sistema operativo no se le pasase el flag correspondiente para admitir en la propiedad --tlsv1.3. Esto suele ocurrir en versiones últimas de macOS. La forma más sencilla es quitar ese flag del comando curl y debería de funcionar todo correctamente. La otra opción es recompilar libcurl.

Llegados a este punto, también vas a necesitar un ‘linker’ que es un programa que usa Rust para unir sus ficheros compilados en uno. Lo normal es que si estas en Linux ya tengas o GCC o Clang instalados por defecto. Si no es tu caso y al intentar compilar un programa de Rust te da errores del ‘linker’ puedes arreglarlo instalando el paquete build-essential.

Si por el contrario estás en macOS, puedes instalar un ‘linker’ ejecutando el siguiente comando:

$ xcode-select --install

Instalación en Windows

En Windows la instalación es un tanto diferente. Primero necesitas instalar las herramientas de desarrolladores que puedes encontrar aquí: https://visualstudio.microsoft.com/downloads/ y asegurarte de seleccionar para instalar, al menos:

  • Desktop Development with C++
  • El SDK para WIndows 10 o 11
  • El pack de lenguaje de inglés, y los otros que tu elijas.

Cuando lo tengas, simplemente tienes que ir a https://www.rust-lang.org/tools/install bajar el instalador y “siguiente”, “siguiente”. Así como Windows sabe hacerlo.

Estés en el S.O que sea, deberías de poder ejecutar el siguiente comando en una terminal y ver la versión del compilador:

$ rustc --version

De nuevo, si ves algún error, cerciórate de que el path al compilador de Rust esté en el PATH.

Hola mundo

Ahora, la mejor forma de establecer una primera toma de contacto con el lenguaje es hacer el mítico “hola mundo”. Para ello, empieza creando una carpeta en tu carpeta de trabajo, llamada por ejemplo “proyectos-rust” y dentro otra carpeta con el nombre “holamundo”:

$ mkdir ~/proyectos
$ cd ~/proyectos
$ mkdir holamundo
$ cd holamundo

Si estás en Windows, ejecuta los siguientes comandos en una CMD:

> mkdir "%USERPROFILE%\proyectos"
> cd /d "%USERPROFILE%\proyectos"
> mkdir holamundo
> cd holamundo

Una vez dentro de la carpeta “holamundo”, abre tu editor preferido y crea un fichero llamado “main.rs” con el siguiente contenido:

fn main() {
    println!("Hola, mundo!");
}

Los ficheros de Rust tienen la extensión .rs. Y si te fijas en el código, estamos creando una función llamada “main” que será el punto de entrada a nuestra aplicación.

Finalmente, dentro de esa función estamos usando “println!” para imprimir el mensaje de nuestro programa. Si te fijas, “println!” tiene una exclamación de cierre al final, no es un error de escritura. Esto es así porque se trata de una macro.

Guarda el fichero y vuelve a la terminal. Ahora vamos a compilar ese fichero con “rustc”:

$ rustc main.rs

Esto nos generará un fichero compilado con el mismo nombre, pero sin extensión. Para ejecutarlo, simplemente haz:

$ ./main

Si todo ha ido bien, deberías de ver:

Hola, Mundo

De nuevo, si estas en Windows para ejecutar el fichero generado por el compilador de Rust, debes de agregarle la extensión “.exe”:

.\main.exe

Gestión de memoria

Como hemos comentado, cada una de las propiedades de este lenguaje que, si bien al principio pueden ser difíciles de entender, han sido cuidadosamente diseñadas para ayudar al programador y empoderarlo.

Una de estas características es el tema de la gestión de memoria y más concretamente el concepto de “ownership” o propiedad que es una de las características más únicas de Rust y que permiten el poder hablar de “seguridad de la memoria” (o en inglés, memory safety) sin necesidad de tener un recolector de basura.

La gestión de memoria en los lenguajes de bajo nivel suele ser un tema peliagudo y que lleva a la mayoría de bugs de seguridad en las aplicaciones. En algunos lenguajes, el programador es el encargado de hacer la reserva y liberación de la memoria de forma explícita por lo que tiene que dedicar especial cuidado para no dejar referencias apuntando a cosas que no existen y que provoque una corrupción de la memoria. En otros, un recolector de basura es el encargado de mirar de forma regular si hay memoria no usada que puede ser liberada.

En Rust en cambio, se introduce el concepto de “propiedad” como un conjunto de reglas que se ejecutan en tiempo de compilación. Si alguna de esas reglas se viola, el programa no compilará. Lo mejor es, que a diferencia por ejemplo del recolector de basura, en Rust los problemas que podrían comprometer la memoria se comprueban compilación, por tanto, en tiempo de ejecución solamente se ejecutan las operaciones de liberación de memoria cuando toquen sin comprometer a la optimización.

Reglas de propiedad

Las reglas de propiedad que son comprobadas por el compilador, son las siguientes:

  • Cada valor en Rust tiene un propietario.
  • Solo puede haber un propietario a la vez.
  • Cuando el propietario se sale del scope, el valor se libera.

El tema del scope es a priori igual que en otros lenguajes. Un valor definido en un scope determinado, será válido durante toda la duración del mismo. En cuanto el scope termine, el valor será liberado:

fn main() {
    let s = "hola mundo"; // a partir de este punto, s es válido

    // código que trabaje con s

    // hasta este punto
} // aquí termina el scope donde s fue creado, por tanto, el valor se libera

Es importante mencionar que los parecidos entre las variables y el scope con otros lenguajes, ocurren siempre cuando hablamos de la memoria “stack”. Cuando hablamos de gestión de memoria, esta puede ser de dos tipos: stack y heap. El stack es una memoria de muy rápido acceso, estructurada en forma de pila LIFO (último en entrar, primero en salir), sin embargo, está limitada en tamaño, refieriéndonos a la cantidad de información que podemos guardar ahí. El heap, en cambio es una memoria menos estructurada y más lenta pero que permite almacenar información de cualquier tamaño (siempre que haya espacio físico).

Prestando la propiedad

Cuando hablamos de valores que se guardan en el stack, al ser una memoria de rápido acceso podemos guardar valores pequeños y copiarlos sin mayor problema:

let x = 1;
let y = x;

Pero la cosa se complica cuando trabajamos con valores que se han de guardar en la memoria heap, ya que al ser necesario buscar un sitio lo suficiente grande y contiguo en el que almacenar nuestros datos, cuando intentamos copiarlos lo que realmente ocurre es que cambia el propietario de esa información.

Por ejemplo, miremos este código:

let s1 = String::from("hola");
let s2 = s1;

En este caso String::from está asignando un trozo de memoria heap para la cadena “hola” y cuando copiamos el contenido de s1 a s2, lo que estamos copiando es el puntero a la posición de memoria donde se encuentra la cadena “hola”.

Si Rust aquí copiase la información, sería una operación muy costosa (imagina en lugar de ser una cadena, fuese todo el contenido de un fichero de 5 GB).

Hasta este punto todo bien. El problema viene cuando intentamos aplicar la tercera regla de la que hablábamos arriba, en la que decíamos que el valor de una variable es liberado (de la memoria) cuando esta se va fuera de scope. En el caso de s1 y s2 las dos se irían fuera de scope a la vez, por lo que Rust intentaría liberar el valor de las dos a la vez y como realmente s1 y s2 apunta a la misma dirección de memoria ocurriría un error conocido como “liberación doble de memoria”. Este error es uno de los más críticos en comprometer la seguridad porque provoca corrupción de la memoria.

Para asegurarnos de que este error no se produzca, cuando hacemos la “copia” en el ejemplo de arriba, Rust considera que la variable s1 ya no es válida y por tanto el nuevo propietario de la información es s2. Así este código no compilará:

let s1 = String::from("hello");
let s2 = s1;

println!("{}, world!", s1);

Y obtendremos un error que nos indicará que el valor se ha tomado prestado (en el println!) después de moverse en la asignación de s2 = s1.

Aplicaciones

Como bien hemos visto Rust es un lenguaje indicado para esas aplicaciones donde haya que hacer una gestión de la memoria activa, que por norma general van a requerir estar optimizados y no estar ligados a las vulnerabilidades que pueda tener un runtime determinado.

A continuación, se listan algunas de las aplicaciones más comunes de este lenguaje de programación:

  • Desarrollo de videojuegos
  • Desarrollo web
  • Sistemas embebidos
  • Herramientas

Debido a que Rust es un lenguaje que agregar seguridad en los accesos a la memoria, permite programación multihilo sin que haya riesgo de acceder a una memoria corrupta, por lo que lo hace idóneo para programación de videojuegos o sistemas embebidos.

Por otra parte, en el desarrollo web puede aportar el poder desarrollar aplicaciones más escalables del lado del servidor y de cliente gracias a web assembly.

Conclusión

En resumen, Rust es un lenguaje que ha ido ganando una popularidad merecida a lo largo de los años y cuya comunidad clama el hecho de que acabará dejando obsoleto a C/C++. Lo que ocurra de verdad, está por verse, pero si que es cierto que Rust jugará un papel muy importante en el futuro del desarrollo de sistemas.

Si te dedicas al desarrollo web y trabajas en la actualidad con JavaScript, puede ser interesante empezar a mirar Rust porque parece que el futuro va a ir en esa línea. Además, conserva ciertas similitudes de sintaxis con este y la curva de aprendizaje inicial puede ser menor. Sin embargo, es importante mencionar que el aprender a gestionar la memoria al 100% con Rust puede conllevar bastante tiempo de estudio y práctica.


Compartir este post

También te puede interesar...

Tecnología

Qué es Rust

17 Febrero 2020 Yanina Muradas
Tecnología

Rust vs Go

07 Agosto 2020 Sandra Domínguez
Tecnología

Por qué aprender a programar en diferentes lenguajes

11 Agosto 2021 Pablo Huet
Artículos
Ver todos