Rust 2018 salió ... pero ¿qué es?

Este artículo fue escrito por Lin Clarke en colaboración con el equipo de desarrollo de Rust ("nosotros" en el texto). También puedes leer la publicación en el blog oficial de Rust.

La primera versión de Rust 2018 se lanzó el 6 de diciembre de 2018. En esta versión, nos centramos en la productividad para que los desarrolladores de Rust comenzaran a trabajar de la manera más eficiente posible.


La línea de tiempo muestra la transición de beta a Rust 2018 y Rust 2015. Está rodeada de iconos para herramientas y cuatro áreas: WebAssembly, embebido, redes y CLI. El círculo rojo (productividad del desarrollador) rodea todo excepto Rust 2015

Pero, en general, no es fácil explicar qué es Rust 2018.

Algunos lo presentan como una nueva versión del lenguaje ... algo así, pero en realidad no. Digo "no realmente", porque aquí la "nueva versión" no significa las nuevas versiones de otros idiomas.

En la mayoría de los otros idiomas, todas las funciones nuevas agregan una nueva versión. La versión anterior no está actualizada.

El sistema Rust funciona de manera diferente. Esto se debe a cómo se desarrolla el lenguaje. Casi todas las nuevas características son 100% compatibles con Rust. No requieren ningún cambio. Esto significa que no hay razón para limitarlos al código Rust 2018. Las versiones más nuevas del compilador continuarán admitiendo el "modo Rust 2015" de forma predeterminada.

Pero a veces el desarrollo de un lenguaje requiere innovación, por ejemplo, una nueva sintaxis. Y esta nueva sintaxis puede romper las bases de código existentes.

Por ejemplo, la función async/await . Inicialmente, no existían tales conceptos en Rust. Pero resultó que estas primitivas son realmente útiles, simplifican la escritura de código asincrónico.

Para esta función, se deben agregar las palabras clave async y await . Pero debe tener cuidado de no romper el código anterior donde async o en await podrían usarse como nombres de variables.

Por lo tanto, agregamos palabras clave en Rust 2018. Aunque la función aún no se ha lanzado, las palabras clave ahora están reservadas. Todos los cambios incompatibles para los próximos tres años de desarrollo (por ejemplo, agregar nuevas palabras clave) se realizan a la vez en Rust 1.31.



Aunque hay cambios incompatibles en Rust 2018, esto no significa que su código se romperá. Incluso con variables async y en await , el código se compilará. Por defecto, el compilador funciona como antes.

Pero si desea usar una de las nuevas funciones, puede elegir el nuevo modo de compilación de Rust 2018. El comando de cargo fix le dirá si necesita actualizar el código para usar las nuevas funciones y automatizar el proceso de hacer cambios. Luego, puede agregar edition=2018 a su Cargo.toml si acepta el uso de nuevas funciones.

Este especificador de versión en Cargo.toml no se aplica a todo el proyecto y no se aplica a sus dependencias. Está limitado a un estante específico. Es decir, puede usar las cajas Rust 2015 y Rust 2018 al mismo tiempo.



Por lo tanto, incluso cuando se usa Rust 2018, todo se ve casi igual a Rust 2015. La mayoría de los cambios se implementan simultáneamente en Rust 2018 y Rust 2015. Solo unas pocas funciones requieren cambios incompatibles.



Rust 2018 no es solo cambios en el idioma principal. Lejos no solo ellos.

Rust 2018 es, en primer lugar, un impulso para mejorar la productividad de los desarrolladores de Rust, en gran parte debido a las herramientas que están fuera del lenguaje, así como a través del desarrollo de aplicaciones específicas y la comprensión de cómo hacer que Rust sea el lenguaje de programación más efectivo para estos casos.

Por lo tanto, puede representar a Rust 2018 como un especificador en Cargo.toml, que se utiliza para incluir varias funciones que requieren cambios incompatibles ...



O puede imaginarlo en un momento en que Rust se convierte en uno de los lenguajes más eficientes para muchas aplicaciones, cuando necesita rendimiento, uso eficiente de los recursos o alta confiabilidad.



Preferimos la segunda versión de la definición. Entonces, echemos un vistazo a todas las mejoras realizadas fuera del idioma, y ​​luego sumérjase en el lenguaje en sí.

Óxido para aplicaciones específicas.


Un lenguaje de programación no puede ser efectivo en sí mismo, de manera abstracta. Es efectivo en una aplicación particular. Por lo tanto, entendimos que no solo era necesario mejorar Rust como lenguaje o herramienta. También es necesario simplificar el uso de Rust en ciertas áreas.



En algunos casos, esto significaba crear un conjunto completamente nuevo de herramientas para un ecosistema completamente nuevo. En otros casos, pulir las funciones existentes y una buena documentación para facilitar la tarea de generar y ejecutar un sistema de trabajo.

El equipo de desarrollo de Rust ha formado grupos de trabajo en cuatro áreas:

  • Montaje web
  • Aplicaciones Embebidas
  • Tareas de red
  • Herramientas de línea de comando

Montaje web


WebAssembly tuvo que crear un conjunto completamente nuevo de herramientas.

Solo el año pasado WebAssembly hizo posible compilar lenguajes como Rust para que se ejecuten en Internet. Desde entonces, Rust se ha convertido rápidamente en el mejor lenguaje para integrarse con las aplicaciones web existentes.



Rust es muy adecuado para el desarrollo web por dos razones:

  1. El ecosistema Cargo Crash funciona de la manera en que la mayoría de los desarrolladores de aplicaciones web están acostumbrados. Combina un montón de pequeños módulos para formar una aplicación más grande. Esto significa que Rust es fácil de usar exactamente donde lo necesita.
  2. El óxido es bajo en recursos y no requiere tiempo de ejecución. No necesitas mucho código. Si tiene un pequeño módulo que hace mucho trabajo informático, implemente algunas líneas Rust para acelerarlo.

Usando web-sys y js-sys del código Rust, es fácil llamar a API web como fetch o appendChild . Y wasm-bindgen facilita el soporte de tipos de datos de nivel superior que WebAssembly no admite de forma nativa.

Después de escribir el módulo Rust WebAssembly, hay herramientas para conectarlo fácilmente al resto de la aplicación web. Puede usar wasm-pack para iniciar automáticamente estas herramientas y ejecutar el módulo en npm si lo desea.

Consulte el libro Rust and WebAssembly para obtener más información .

Que sigue


Después del lanzamiento de Rust 2018, los desarrolladores planean discutir con la comunidad en qué direcciones trabajar más.

Aplicaciones Embebidas


Para el desarrollo integrado, era necesario aumentar la estabilidad de la funcionalidad existente.

Teóricamente, Rust siempre ha sido un buen lenguaje para aplicaciones integradas. Este es un kit de herramientas moderno, que era muy escaso para los desarrolladores, y funciones de lenguaje de alto nivel muy convenientes. Todo esto sin carga innecesaria en la CPU y la memoria. Por lo tanto, Rust es ideal para incrustar.

Pero en la práctica resultó diferente. El canal estable carecía de las funciones necesarias. Además, para su uso en dispositivos integrados, era necesario cambiar la biblioteca estándar. Esto significa que las personas tuvieron que compilar su propia versión de la caja principal de Rust (la caja que se usa en cada aplicación de Rust para proporcionar los bloques de construcción básicos de Rust: funciones integradas y primitivas).



Como resultado, los desarrolladores dependían de la versión experimental de Rust. Y en ausencia de pruebas automáticas, el ensamblaje experimental a menudo no funcionaba en microcontroladores.

Para solucionar esto, los desarrolladores intentaron transferir todas las funciones necesarias a un canal estable, agregar pruebas al sistema CI para microcontroladores. Esto significa que cambiar un componente de escritorio no interrumpirá la versión integrada.

Con tales cambios, el desarrollo de sistemas embebidos en Rust se está moviendo del campo de los experimentos avanzados al campo de la eficiencia normal.

Para obtener más información, consulte el libro Rust for Embedded Systems .

Que sigue


Este año, Rust obtuvo un muy buen apoyo para la popular familia ARM Cortex-M. Sin embargo, muchas arquitecturas aún no están bien soportadas. Rust necesita expandirse para proporcionar soporte similar para otras arquitecturas.

Tareas de red


Para trabajar en la red, era necesario integrar una abstracción clave en el lenguaje: async/await . Por lo tanto, los desarrolladores pueden usar modismos estándar de Rust incluso en código asincrónico.

En las tareas de red, a menudo tiene que esperar. Por ejemplo, una respuesta a una solicitud. Si el código es síncrono, el trabajo se detendrá: el núcleo del procesador en el que se ejecuta el código no puede hacer nada hasta que llegue una solicitud. Pero en el código asíncrono, dicha función se puede poner en modo de espera, mientras que el núcleo de la CPU hará el resto.

La programación asincrónica también es posible en Rust 2015, y esto tiene muchas ventajas. En aplicaciones de alto rendimiento, la aplicación del servidor manejará muchas más conexiones a cada servidor. Las aplicaciones integradas en pequeñas CPU de un solo subproceso optimizan el uso de un solo subproceso.

Pero estas ventajas van acompañadas de un gran inconveniente: para dicho código, la verificación de préstamo no funciona y debe usar modismos de óxido no estándar (y ligeramente confusos). Este es el beneficio de async/await . Esto le da al compilador la información necesaria para probar los préstamos de llamadas a funciones asíncronas.

Las palabras clave para async/await implementan en la versión 1.31, aunque actualmente no son compatibles con la implementación. La mayor parte del trabajo está hecho, y la función debería estar disponible en la próxima versión.

Que sigue


Además del desarrollo efectivo de bajo nivel, Rust puede proporcionar un desarrollo más eficiente de aplicaciones de red en un nivel superior.

Muchos servidores realizan tareas rutinarias: analizar URL o trabajar con HTTP. Si los convierte en componentes, abstracciones comunes que se comparten como cajas, entonces será fácil conectarlos entre sí, formando todo tipo de configuraciones de servidor y marco.

Se ha creado un marco experimental de Tide para desarrollar y probar componentes.

Herramientas de línea de comando


Para las herramientas de línea de comandos, era necesario combinar pequeñas bibliotecas de bajo nivel en abstracciones de alto nivel y pulir algunas herramientas existentes.

Para algunos scripts, bash es ideal. Por ejemplo, simplemente invocar otras herramientas de shell y pasar datos entre ellas.

Pero Rust es una gran opción para muchas otras herramientas. Por ejemplo, si crea una herramienta compleja como ripgrep o una herramienta CLI además de la funcionalidad de una biblioteca existente.

Rust no requiere tiempo de ejecución y se compila en un solo binario estático, lo que simplifica la distribución del programa. Y obtienes abstracciones de alto nivel que no están en otros lenguajes, como C y C ++.

¿Qué más puede mejorar el óxido? Por supuesto, abstracciones de un nivel aún más alto.

Con abstracciones de nivel superior, un CLI listo para usar se ensambla rápida y fácilmente.

Un ejemplo de tal abstracción es la biblioteca de pánico humano . En ausencia de dicha biblioteca, en caso de falla, el código CLI probablemente devolverá todo el retroceso. Pero no es muy interesante para los usuarios. Puede agregar un manejo de errores personalizado, pero es difícil.

Con la biblioteca de pánico humano, la salida irá automáticamente al archivo de volcado de error. El usuario verá un mensaje informativo que ofrece informar un problema y descargar el archivo de volcado.



Comenzar a desarrollar herramientas de CLI también se ha vuelto más fácil. Por ejemplo, la biblioteca confy automatiza su configuración. Él solo pregunta dos cosas:

  • ¿Cuál es el nombre de la aplicación?
  • ¿Qué parámetros de configuración desea proporcionar (que define como una estructura que se puede serializar y deserializar)?

Confy determinará todo lo demás por sí solo.

Que sigue


Extrajimos muchas tareas para la CLI. Pero hay algo más que abstraer. Vamos a lanzar más bibliotecas de alto nivel.

Herramientas de óxido




Cuando escribe en cualquier idioma, trabaja con sus herramientas: comenzando con el editor y continuando con otras herramientas en todas las etapas de desarrollo y soporte.

Esto significa que un lenguaje efectivo depende de herramientas efectivas.

Aquí hay algunas herramientas nuevas (y mejoras a las existentes) en Rust 2018.

Soporte IDE


Por supuesto, el rendimiento depende de la transferencia rápida y sin problemas del código de la mente del desarrollador a la pantalla de la computadora. Aquí es donde el soporte IDE es crucial. Para hacer esto, necesitamos herramientas que puedan "explicar" el IDE al significado del código Rust: por ejemplo, sugerir opciones significativas para el autocompletado de cadenas.

En Rust 2018, la comunidad se centró en las características requeridas por el IDE. Con el advenimiento de Rust Language Server e IntelliJ Rust, muchos IDE ahora son totalmente compatibles con Rust.

Compilación más rápida


Mejorar el rendimiento del compilador significa acelerarlo. Esto es lo que hicimos.

Anteriormente, cuando compilaba la caja Rust, el compilador volvía a compilar todos los archivos de la caja. La compilación incremental ahora se implementa: compila solo aquellas partes que han cambiado. Junto con otras optimizaciones, esto hizo que el compilador Rust fuera mucho más rápido.

rustfmt


La eficiencia también requiere que nunca discutamos sobre las reglas de formato de código o que arreglemos manualmente los estilos de otras personas.

La herramienta rustfmt ayuda con esto: reformateará automáticamente el código de acuerdo con el estilo predeterminado (por el cual la comunidad ha alcanzado un consenso ). Rustfmt garantiza que todo el código Rust coincida con el mismo estilo, como el formato clang para C ++ o Prettier para JavaScript.

Clippy


A veces es bueno tener un consultor experimentado cerca que le brinde consejos sobre las mejores prácticas para escribir código. Esto es lo que hace Clippy: comprueba el código mientras lo ve y sugiere modismos estándar.

rustfix


Pero si tiene una base de código antigua con modismos obsoletos, entonces verificar y corregir independientemente el código puede ser agotador. Solo quiere que alguien haga correcciones a toda la base de código.

En estos casos, rustfix automatiza el proceso. Aplica simultáneamente reglas de herramientas como Clippy y actualiza el código antiguo de acuerdo con los modismos de Rust 2018.

Cambios al óxido mismo


Los cambios en el ecosistema han aumentado significativamente la eficiencia de la programación. Pero algunos problemas solo pueden resolverse mediante cambios en el lenguaje mismo.



Como dijimos en la introducción, la mayoría de los cambios de idioma son totalmente compatibles con el código Rust existente. Todos estos cambios son parte de Rust 2018. Pero como no rompen nada, funcionan en cualquier código Rust ... incluso en el antiguo.

Veamos las características importantes que se agregan a todas las versiones. Luego mira una breve lista de características de Rust 2018.

Nuevas funciones para todas las versiones.


Aquí hay un pequeño ejemplo de las nuevas características que están (o estarán) en todas las versiones del lenguaje.

Verificación de préstamos más precisa


Una gran ventaja de Rust es su verificación de préstamo. Asegura que el código sea seguro para la memoria. Pero esta también es una característica bastante complicada para los novatos en Rust.

Parte de la dificultad radica en aprender nuevos conceptos. Pero hay otra parte ... La prueba de préstamos a veces rechaza el código que parece funcionar desde el punto de vista de un programador que comprende completamente el concepto de seguridad de la memoria.


No puede pedir prestada una variable porque ya está prestada

Esto sucede porque se suponía que la vida útil del préstamo se extendía hasta el final de su campo, por ejemplo, hasta el final de la función en la que se encuentra la variable.

Esto significaba que incluso si la variable terminaba de funcionar con el valor y ya no intentaba acceder, a otras variables aún se les niega el acceso a este valor hasta el final de la función.

Para corregir la situación, hicimos el cheque más inteligente. Ahora ve cuándo la variable realmente ha terminado de usar el valor. Después de eso, no bloquea el uso de datos.



Si bien esto está disponible solo en Rust 2018, pero en un futuro cercano, la función se agregará a todas las demás versiones. Pronto escribiremos más sobre este tema.

Macros procesales en óxido estable


Rust tenía macros antes de Rust 1.0. Pero en Rust 2018, se realizaron serias mejoras, por ejemplo, aparecieron macros de procedimiento. Le permiten agregar su propia sintaxis a Rust.

Rust 2018 ofrece dos tipos de macros de procedimiento:

Macros de funciones


Las macros similares a funciones le permiten crear objetos que parecen llamadas a funciones normales, pero que en realidad se ejecutan en tiempo de compilación. Toman un código y dan otro, que el compilador luego inserta en el binario.

Existieron antes, pero con limitaciones. Una macro solo puede ejecutar la declaración de coincidencia. No tenía acceso para ver todos los tokens en el código entrante.

Pero con las macros de procedimiento, obtienes la misma entrada que el analizador: la misma secuencia de tokens. Esto significa que puede crear macros mucho más potentes como funciones.

Macros tipo atributo


Si está familiarizado con decoradores en lenguajes como JavaScript, las macros de atributos son muy similares. Le permiten anotar fragmentos de código Rust que deben procesarse previamente y convertirse en otra cosa.

La macro derive hace exactamente eso. Cuando lo coloca sobre una estructura, el compilador toma esa estructura (después de analizarla como una lista de tokens) y la procesa. En particular, agrega una implementación básica de funciones desde el rasgo.

Más préstamos ergonómicos en las comparaciones


Hay un cambio simple.

Anteriormente, si quería pedir prestado algo e intentaba hacer coincidir, tenía que agregar una sintaxis extraña:



Ahora, en lugar de &Some(ref s) simplemente escribimos Some(s) .

Nuevas características de Rust 2018


La parte más pequeña de Rust 2018 es características específicas de esta versión. Aquí hay un pequeño conjunto de cambios en Rust 2018.

Palabras clave


Rust 2018 agregó algunas palabras clave:

  • try
  • async/await

Estas características aún no están completamente implementadas, pero las palabras clave se agregan en Rust 1.31. Por lo tanto, en el futuro no tendremos que introducir nuevas palabras clave (lo que se convertiría en un cambio incompatible) cuando implementemos estas funciones.

Sistema modular


Un gran dolor para los novatos en Rust es el sistema modular. Y está claro por qué. Era difícil entender por qué Rust elige un módulo en particular. Para solucionar esto, hicimos algunos cambios en el mecanismo de ruta.

Por ejemplo, si importó un bastidor, puede usarlo en la ruta en el nivel superior. Pero si mueve cualquier código a un submódulo, ya no funcionará.

 // top level module extern crate serde; // this works fine at the top level impl serde::Serialize for MyType { ... } mod foo { // but it does *not* work in a sub-module impl serde::Serialize for OtherType { ... } } 

Otro ejemplo es el prefijo ::, que se usa tanto para la raíz de la caja como para la caja externa. Es difícil entender lo que está ante nosotros.

Lo hicimos más explícito. Ahora, si desea hacer referencia a la caja raíz, utilice el prefijo crate::. Esta es solo una de las mejoras para la claridad.

Si desea que el código actual use las capacidades de Rust 2018, lo más probable es que necesite actualizar el código para tener en cuenta las nuevas rutas. Pero no es necesario hacer esto manualmente. Antes de agregar el especificador de versión a Cargo.toml, simplemente ejecútelo cargo fixy rustfixrealice los cambios necesarios.

Información adicional


Toda la información sobre la nueva versión del idioma está contenida en la Guía Rust 2018 .

Source: https://habr.com/ru/post/es432564/


All Articles