<a href="https://www.rust-lang.org/" target="_blank">Rust</a> es un <a href="https://hackernoon.com/tagged/language" target="_blank">lenguaje</a> de <a href="https://hackernoon.com/tagged/programming" target="_blank">programación</a> moderno a nivel de sistemas diseñado teniendo en cuenta la seguridad. Proporciona abstracciones de costo cero, genéricos, características funcionales y mucho más. Recientemente me embarqué en un esfuerzo por aprender Rust correctamente y quería compartir algunos de mis pensamientos.
Rust es un lenguaje de programación moderno a nivel de sistemas diseñado teniendo en cuenta la seguridad. Proporciona abstracciones de costo cero, genéricos, características funcionales y mucho más. Recientemente me embarqué en un esfuerzo por aprender Rust correctamente y quería compartir algunos de mis pensamientos.
Hasta hace poco, había escrito solo un puñado de pequeños programas en Rust, y después de leer la mitad de "Programación de Rust", realmente no conocía Rust. Pensé que una buena manera de conocer el idioma era resolver los 189 problemas del libro "Cracking the Coding Interview" . No solo los resolvería con Rust, sino que decidí hacerlo en vivo en Twitch . No soy ajeno a dar charlas sobre tecnología o programar frente a una audiencia, pero tratar de aprender un lenguaje de programación y explicar lo que estaba haciendo, vivir para que el mundo lo viera, fue algo nuevo para mí.
Las cosas comenzaron un poco difíciles: contratiempos técnicos, problemas de transmisión, problemas de herramientas, y al principio tuve dificultades para entender el paradigma de la memoria. Tratar de hacer eso, al mismo tiempo que explicaba lo que estaba haciendo a la gente, fue eh... complicado .
Me tomó alrededor de 8 horas implementar una lista enlazada: grabé dos transmisiones de 4 horas de mí mismo tratando de descubrir cómo usar correctamente Rc, RefCell y Box. Por un tiempo sentí que solo estaba golpeando el teclado intentando combinaciones aleatorias hasta que algo se atascó. Lo sorprendente es que la gente se sintonizó para mirar. Debo haber estado haciendo algo bien.
Después de leer un poco sin conexión (y seguir el muy útil libro " Aprendiendo Rust con demasiadas listas enlazadas en su totalidad"), y los conceptos comenzaron a hacer clic para mí. Después de terminar la implementación de mi lista enlazada, las cosas se volvieron más fáciles.
Lista enlazada en Rust. VSCode tiene una estrecha integración con RLS
Ahora estoy en el capítulo 4 del libro, y siento que he alcanzado mi ritmo. Rust se siente natural, productivo y extremadamente satisfactorio una vez que se compila. Rust está fuertemente tipado y proporciona excelentes mensajes de compilación: si logró apaciguar al compilador, existe una buena posibilidad de que su código funcione, a menos que haya fallas de lógica.
Una característica encantadora de Rust es lo útil que puede ser el compilador. Los mensajes del compilador para código C++, por ejemplo, son notoriamente difíciles de descifrar. Si bien Clang ha logrado grandes avances con sus mensajes de error, el compilador de Rust es otro orden de magnitud más útil.
Ejemplo de salida de error de rustc
Voy a resumir algunos de mis hallazgos hasta ahora. Esto se basa en mis reacciones iniciales y reconozco mi falta de experiencia en Rust, pero aún puede ser interesante para otros ver cómo se compara su experiencia con la mía. Lamentablemente, admito que no he investigado minuciosamente todos los temas a continuación, por lo que es posible que tenga información desactualizada o inexacta.
Idioma: El Bueno
En primer lugar, felicitaciones al equipo de Rust y a todos los que han contribuido al proyecto. Esta ha sido una de las experiencias de aprendizaje de lenguajes de programación más divertidas que he tenido. No sé si Rust captará la atención de los desarrolladores de la misma manera que lo han hecho otros lenguajes, pero creo que llegó para quedarse. En los detalles:
El código de Rust es bastante fácil de leer y no sufre la sintaxis difícil de analizar de lenguajes como C++ o Scala. Parece tener lo que espero que tenga, y el desafío es simplemente averiguar qué función llamar.
Tener características funcionales como map() , filter() , find() , etc. es una delicia. Definir funciones de orden superior y pasarles cierres es pan comido. No hace que la programación funcional sea tan fácil como un lenguaje como Ruby, pero está cerca. De hecho, es sorprendente lo fácil que es para un lenguaje que funciona de manera comparable a C/C++.
Rust lo obliga a pensar mucho sobre la asignación de memoria, porque no tiene otra opción. Al final, significa que el código descuidado es difícil de escribir y el buen código es fácil de escribir. Estas abstracciones también se asignan directamente a la escritura de código concurrente seguro.
Las abstracciones de costo cero de Rust facilitan la escritura de un buen código sin agregar gastos generales. Los rasgos proporcionan abstracción de programación moderna sin penalizar el rendimiento.
El código de Rust es seguro (siempre que no use la palabra clave unsafe o llame a bibliotecas C inseguras)
Result y Option de Rust proporcionan una buena manera de tratar con funciones que pueden devolver un valor o variables que pueden contener un valor. Un patrón común en C, C++ e incluso Java es que las funciones devuelvan un puntero nulo cuando no hay nada que devolver. En la mayoría de los casos, cuando esto sucede de forma inesperada, resulta en que alguien está pasando un mal momento.
Lenguaje: Lo Malo
Encuentro la necesidad de unwrap() , as_ref() y borrow() un poco detallado a veces. Desearía que hubiera algo de azúcar en la sintaxis para reducir la cantidad de veces que tengo que encadenar estas llamadas en diferentes patrones. Frecuentemente me encuentro escribiendo código similar a option.as_ref().unwrap().borrow() , lo cual se siente asqueroso.
Hay ciertas compensaciones que el compilador debe hacer para poder compilar el código en un tiempo razonable. Como resultado, hay algunos casos en los que rustc no puede inferir un tipo, o necesita ayuda humana para compilar el código. Para mí, he descubierto que a veces puede ser muy difícil averiguar qué necesita el compilador y por qué no puede resolverlo por mí.
Algunas cosas ocasionalmente se sienten demasiado detalladas. Por ejemplo, convertir entre str y String , o pasar una referencia en lugar de un valor a una función parece algo que el compilador podría resolver por mí. Estoy seguro de que hay una buena razón por la que es así, pero ocasionalmente parece que rustc está siendo demasiado correcto .
Tener que manejar cada Result de cada función es bueno; significa que el programador tiene que pensar en lo que sucede con cada llamada de función. A veces se siente tedioso. el ? El operador puede reducir parte de la verbosidad, pero no hay una buena manera de generalizar para manejar los tipos de fallas. Las cajas como fail y error-chain facilitan esto, pero aún necesita definir explícitamente un caso para cada tipo de error que pueda ocurrir.
Idioma: Lo Feo
Macros: WTF? Las macros de Rust se sienten como un giro a la izquierda en comparación con el resto del lenguaje. Para ser justos, todavía no he podido asimilarlos y, sin embargo, se sienten fuera de lugar, como un extraño apéndice que se agrega después de que se diseñó el lenguaje, inspirado en Perl. Eventualmente me tomaré un tiempo para comprenderlos correctamente en el futuro, pero ahora mismo quiero evitarlos. Como la peste.
Herramientas: lo bueno
Rust proporciona herramientas decentes y se integra con IDE como VSCode a través de RLS . RLS brinda soporte para la eliminación de pelusas, la finalización de código, la verificación de sintaxis y el formateo sobre la marcha.
Cargo es el poderoso administrador de paquetes de Rust: probablemente se familiarice con él si prueba Rust. En su mayor parte, trabajar con Cargo es un placer. Ya hay una gran cantidad de complementos para Cargo que brindan funciones adicionales, como cobertura de código .
Cargo también es un sistema de compilación y se puede usar para ejecutar pruebas unitarias y de integración. Configurar su compilación y dependencias es muy fácil con su sintaxis TOML un tanto declarativa.
Cargo se integra con crates.io, que es la fuente definitiva para proyectos Rust de código abierto. Al igual que PyPi o RubyGems, encontrará casi todos los demás paquetes de Rust alojados en crates.io.
rustup es la herramienta preferida para administrar su instalación de Rust. Puede seleccionar canales estables, beta o nocturnos e instalar compilaciones específicas de todas las versiones anteriores. También te permite instalar componentes como clippy y rustfmt
clippy es un linter de código imprescindible si eres un perfeccionista como yo. Le ayudará a aprender a la manera de Rust, y puede detectar muchos errores comunes que de otro modo no notaría. Para mí, clippy fue útil cuando conocía una forma de resolver algo, pero no conocía la forma correcta .
rustfmt es un formateador de código obstinado para Rust. En mi opinión, los formateadores obstinados son el camino a seguir. No hay discusión sobre el formato del código cuando todo se adhiere al mismo estándar.
sccache , un caché del compilador, acelerará las cosas al reducir los tiempos de compilación. Sin embargo, tenga cuidado, sccache no funciona con RLS, por lo que no puede usarlo con su IDE.
Herramientas: lo malo
Bien, bien, antes de continuar con los problemas con Rust, todos debemos reconocer que este es un trabajo en progreso. Las herramientas de Rust han llegado muy lejos, muy rápido, pero creo que todavía tiene un largo camino por recorrer. Voy a destacar algunas de las cosas que necesitan mejorar:
La compilación se siente lenta. No solo es lento, sino que a menudo tengo que recompilar paquetes. Entiendo la necesidad, pero todavía es molesto a veces. sccache ayuda, pero todavía se siente lento. Hay algunas formas de mitigar esto, como usar cargo check en lugar de cargo build .
RLS usa corredor para completar el código, y encuentro que es impredecible en el mejor de los casos (al menos en VSCode). A menudo, las funciones para las que espero que se completen no existen, y las funciones que no existen aparecen como opciones de finalización. No he realizado un análisis exhaustivo, pero las sugerencias parecen ser correctas solo alrededor del 75% de las veces. La causa de esto puede deberse simplemente a la lentitud de RLS.
Sin REPL: esto puede ser injusto, ya que tampoco hay un REPL de C++ decente, pero muchos lenguajes vienen con un REPL en estos días. Hay un problema abierto en GitHub sobre esto. Un buen REPL no es necesario, pero sería útil.
Herramientas: lo feo
RLS es lento, con errores y accidentado. Para mí, al menos, encuentro que con frecuencia necesito reiniciar RLS dentro de VSCode. RLS es una gran herramienta, pero se siente como si fuera beta en el mejor de los casos. Me encuentro teniendo que hacer una pausa y esperar a que RLS se ponga al día para asegurarme de que no estoy escribiendo un código incorrecto. A veces creo que sería mejor simplemente deshabilitar RLS, escribir el código y luego intentar compilarlo como en los viejos tiempos cuando hacía toda mi codificación en Vim. Es casi como si RLS se hubiera convertido en una muleta y más en una distracción.
Bibliotecas: lo bueno
Sorprendentemente gran cantidad de bibliotecas disponibles en el ecosistema de Rust. Parece como si hubiera una fiebre del oro para ejecutar e implementar todas las bibliotecas de Rust, y conseguir que su nombre sea inmortalizado en la historia de Rust. Puede encontrar la mayor parte de lo que esperaría en crates.io o GitHub. A menudo me sorprende cómo cada búsqueda muestra 2 o 3 implementaciones diferentes de lo que estoy buscando.
La mayoría de las bibliotecas que he usado funcionan como se esperaba y muchas han superado las expectativas. Esta es una distinción sutil e importante de la alternativa, que son bibliotecas que no funcionan.
Biblioteca Pública de Nueva York en 1908, de la Biblioteca del Congreso
Bibliotecas: Lo malo
Aunque hay muchas bibliotecas, he descubierto que muchas de ellas están incompletas, inmaduras o completamente abandonadas. Parece que la comunidad de Rust todavía está en sus inicios, pero está mejorando cada día.
A veces hay… demasiadas opciones . Por ejemplo, quería usar una biblioteca de registro y descubrí que hay una larga lista de opciones para elegir . Tener muchas opciones está bien, pero para algo como esto solo quiero que me digan qué usar. El ecosistema de Java tiene un problema similar con java.util.logging, log4j, logback, log4j2, slf4j y tinylog. Hasta el día de hoy, todavía no sé qué biblioteca de registro de Java es la adecuada para usar. Con Rust, simplemente decidí usar env_logger porque es la primera opción en la lista.
Si bien no es tan malo como el ecosistema Node.js, la lista de dependencias para cada biblioteca se ha vuelto bastante larga. Escribí un pequeño bot de GitHub llamado LabHub , y todavía me sorprende la cantidad de dependencias que se extraen (181 cajas, si te lo estás preguntando). Para mí, esto sugiere fragmentación y duplicación, lo que tal vez podría mejorarse graduando lentamente algunas funciones muy necesarias en la biblioteca estándar (algo que C++ ha hecho muy lentamente).
Bibliotecas: La fea
Noté que, junto con una larga lista de dependencias para una aplicación relativamente simple, estaba compilando diferentes versiones de las mismas bibliotecas varias veces . Creo que Cargo está tratando de ser inteligente para mantener la compatibilidad con versiones anteriores; está haciendo conjeturas sobre qué bibliotecas incluir en función de las versiones semánticas. Lo que me preocupa de esto es lo que sucede cuando tienes una biblioteca que depende de una versión antigua y rota de otra biblioteca que también tiene una vulnerabilidad. No tengo ninguna duda de que los autores de Rust ya han considerado esto, pero todavía parece extraño. Para ser justos, lidiar con dependencias de dependencias es un problema muy complicado. Afortunadamente, hay una herramienta de árbol para Cargo que puede ayudar a resolver estas cosas, y luego puede forzar una dependencia para actualizar sus dependencias.
10 bibliotecas diferentes con 2 versiones diferentes en el mismo paquete
Pensamientos finales
Rust es un gran lenguaje. Si la programación es algo que te apasiona, pruébalo. Espero que lo disfruten.
Yo tratando de tener un pensamiento
Acerca de mí: He estado escribiendo código desde que tenía 12 años, he contribuido a varios proyectos de código abierto diferentes y he trabajado en una variedad de compañías, incluidas Airbnb, Mesosphere y Citadel. Encuéntrame en GitHub engithub.com/brndnmtthws, Twitch entwitch.tv/brndnmtthwso Twitter entwitter.com/brndnmtthws.