Rust 2018 saiu ... mas o que é?

Este artigo foi escrito por Lin Clarke em colaboração com a equipe de desenvolvimento Rust (“nós” no texto). Você também pode ler a postagem no blog oficial da Rust.

A primeira versão do Rust 2018 foi lançada em 6 de dezembro de 2018. Nesta versão, focamos na produtividade para que os desenvolvedores do Rust passassem a trabalhar da maneira mais eficiente possível.


A linha do tempo mostra a transição do beta para o Rust 2018 e o Rust 2015. Ela é cercada por ícones de ferramentas e quatro áreas: WebAssembly, incorporado, rede e CLI. O círculo vermelho - produtividade do desenvolvedor - envolve tudo, exceto o Rust 2015

Mas, em geral, não é fácil explicar o que é Rust 2018.

Alguns a apresentam como uma nova versão da linguagem ... algo assim, mas não realmente. Eu digo "não realmente", porque aqui a "nova versão" não significa as novas versões de outros idiomas.

Na maioria dos outros idiomas, todos os novos recursos adicionam uma nova versão. A versão anterior não é atualizada.

O sistema Rust opera de maneira diferente. Isto é devido à forma como a linguagem se desenvolve. Quase todos os novos recursos são 100% compatíveis com o Rust. Eles não exigem nenhuma alteração. Isso significa que não há razão para limitá-los ao código do Rust 2018. As versões mais recentes do compilador continuarão suportando o "modo Rust 2015" por padrão.

Mas, às vezes, o desenvolvimento de uma linguagem requer inovação, por exemplo, uma nova sintaxe. E essa nova sintaxe pode quebrar as bases de código existentes.

Por exemplo, a função async/await . Inicialmente, não havia tais conceitos no Rust. Porém, essas primitivas são realmente úteis, pois simplificam a gravação de código assíncrono.

Para esta função, as palavras async chave async e await devem ser adicionadas. Mas você deve tomar cuidado para não quebrar o código antigo, onde async ou await podem ser usados ​​como nomes de variáveis.

Assim, adicionamos palavras-chave no Rust 2018. Embora a função ainda não tenha sido lançada, as palavras-chave agora estão reservadas. Todas as alterações incompatíveis para os próximos três anos de desenvolvimento (por exemplo, adicionando novas palavras-chave) são feitas por vez no Rust 1.31.



Embora haja alterações incompatíveis no Rust 2018, isso não significa que seu código será quebrado. Mesmo com variáveis async e await , o código será compilado. Por padrão, o compilador funciona como antes.

Mas se você quiser usar uma das novas funções, poderá escolher o novo modo de compilação do Rust 2018. O comando cargo fix irá informar se você precisa atualizar o código para usar as novas funções e automatizar o processo de fazer alterações. Em seguida, você pode adicionar edition=2018 ao seu Cargo.toml se concordar com o uso de novas funções.

Esse especificador de versão no Cargo.toml não se aplica a todo o projeto e não se aplica às suas dependências. É limitado a um rack específico. Ou seja, você pode usar as caixas Rust 2015 e Rust 2018 ao mesmo tempo.



Portanto, mesmo ao usar o Rust 2018, tudo se parece com o Rust 2015. A maioria das alterações é introduzida simultaneamente no Rust 2018 e no Rust 2015. Apenas algumas funções exigem alterações incompatíveis.



O Rust 2018 não é apenas uma mudança no idioma principal. Longe não apenas eles.

O Rust 2018 é, antes de tudo, um ímpeto para melhorar a produtividade dos desenvolvedores do Rust, em grande parte graças a ferramentas que estão fora da linguagem, além do desenvolvimento de aplicativos específicos e do entendimento de como tornar o Rust a linguagem de programação mais eficaz para esses casos.

Assim, você pode representar o Rust 2018 como um especificador no Cargo.toml, que é usado para incluir várias funções que exigem alterações incompatíveis ...



Ou você pode imaginá-lo em um momento em que o Rust se torna uma das linguagens mais eficientes para muitos aplicativos - quando você precisa de desempenho, uso eficiente dos recursos ou alta confiabilidade.



Nós preferimos a segunda versão da definição. Então, vamos olhar para todas as melhorias feitas fora do idioma e depois mergulhar no próprio idioma.

Ferrugem para aplicações específicas


Uma linguagem de programação não pode ser eficaz em si mesma, abstratamente. É eficaz em uma aplicação específica. Portanto, entendemos que não era apenas necessário melhorar o Rust como uma linguagem ou ferramenta. Também é necessário simplificar o uso do Rust em certas áreas.



Em alguns casos, isso significava criar um conjunto de ferramentas completamente novo para um ecossistema completamente novo. Em outros casos, polir as funções existentes e a boa documentação para facilitar a criação e a execução de um sistema em funcionamento.

A equipe de desenvolvimento da Rust formou grupos de trabalho em quatro áreas:

  • Webassembly
  • Aplicativos Incorporados
  • Tarefas de rede
  • Ferramentas de linha de comando

Webassembly


O WebAssembly teve que criar um conjunto completamente novo de ferramentas.

Somente no ano passado o WebAssembly tornou possível compilar idiomas como o Rust para rodar na Internet. Desde então, o Rust se tornou rapidamente o melhor idioma para integração com aplicativos da web existentes.



O Rust é adequado para o desenvolvimento da Web por dois motivos:

  1. O Ecossistema Cargo Crash funciona da maneira que a maioria dos desenvolvedores de aplicativos da web está acostumada. Combine vários módulos pequenos para formar um aplicativo maior. Isso significa que o Rust é fácil de usar exatamente onde você precisa.
  2. A ferrugem é baixa em recursos e não requer tempo de execução. Você não precisa de muito código. Se você possui um módulo minúsculo que trabalha muito com computação pesada, implemente algumas linhas Rust para agilizá-lo.

Usando web-sys e js-sys do código Rust, é fácil chamar APIs da web, como fetch ou appendChild . E o wasm-bindgen facilita o suporte a tipos de dados de nível superior aos quais o WebAssembly não oferece suporte nativo.

Após escrever o módulo Rust WebAssembly, existem ferramentas para conectá-lo facilmente ao restante do aplicativo da web. Você pode usar o wasm-pack para ativar automaticamente essas ferramentas e executar o módulo no npm, se desejar.

Veja o livro Rust and WebAssembly para obter mais informações .

O que vem a seguir?


Após o lançamento do Rust 2018, os desenvolvedores planejam discutir com a comunidade quais as direções a seguir.

Aplicativos Incorporados


Para o desenvolvimento incorporado, era necessário aumentar a estabilidade da funcionalidade existente.

Teoricamente, o Rust sempre foi uma boa linguagem para aplicativos incorporados. Este é um kit de ferramentas moderno, que faltava muito para os desenvolvedores e funções de linguagem de alto nível muito convenientes. Tudo isso sem carga desnecessária na CPU e na memória. Assim, o Rust é ótimo para embutidos.

Mas, na prática, ficou diferente. O canal estável não possuía as funções necessárias. Além disso, para uso em dispositivos incorporados, era necessário alterar a biblioteca padrão. Isso significa que as pessoas precisavam compilar sua própria versão do engradado principal do Rust (o engradado usado em todos os aplicativos Rust para fornecer os blocos básicos de construção do Rust - funções integradas e primitivas).



Como resultado, os desenvolvedores dependiam da versão experimental do Rust. E, na ausência de testes automáticos, a montagem experimental geralmente não funcionava em microcontroladores.

Para corrigir isso, os desenvolvedores tentaram transferir todas as funções necessárias para um canal estável, adicionar testes ao sistema de CI para microcontroladores. Isso significa que alterar um componente da área de trabalho não interromperá a versão interna.

Com essas mudanças, o desenvolvimento de sistemas embarcados no Rust está passando do campo de experimentos avançados para o campo da eficiência normal.

Para obter mais informações, consulte o livro Rust for Embedded Systems .

O que vem a seguir?


Este ano, Rust obteve um suporte realmente bom para a popular família ARM Cortex-M. No entanto, muitas arquiteturas ainda não são bem suportadas. A ferrugem precisa ser expandida para fornecer suporte semelhante para outras arquiteturas.

Tarefas de rede


Para trabalhar na rede, foi necessário incorporar uma abstração importante no idioma: async/await . Assim, os desenvolvedores podem usar expressões padrão do Rust, mesmo em código assíncrono.

Nas tarefas de rede, você geralmente precisa esperar. Por exemplo, uma resposta a uma solicitação. Se o código for síncrono, o trabalho será interrompido: o núcleo do processador no qual o código é executado não poderá fazer nada até que uma solicitação chegue. Mas no código assíncrono, essa função pode ser colocada no modo de espera, enquanto o núcleo da CPU faz o resto.

A programação assíncrona também é possível no Rust 2015, e há muitas vantagens nisso. Em aplicativos de alto desempenho, o aplicativo do servidor manipula muito mais conexões com cada servidor. Os aplicativos incorporados em pequenas CPUs de thread único otimizam o uso de um único thread.

Mas essas vantagens são acompanhadas de uma grande desvantagem: para esse código, a verificação do empréstimo não funciona e você precisa usar idiomas de ferrugem não padrão (e um pouco confusos). Esse é o benefício de async/await . Isso fornece ao compilador as informações necessárias para testar empréstimos de chamadas de função assíncronas.

Palavras-chave para async/await implementadas na versão 1.31, embora não sejam atualmente suportadas pela implementação. A maior parte do trabalho está concluída e o recurso deve estar disponível na próxima versão.

O que vem a seguir?


Além do desenvolvimento eficaz de baixo nível, o Rust pode fornecer um desenvolvimento mais eficiente de aplicativos de rede em um nível superior.

Muitos servidores realizam tarefas de rotina: analisam URLs ou trabalham com HTTP. Se você transformá-los em componentes - abstrações comuns que são compartilhadas como caixas -, será fácil conectá-los uns aos outros, formando todos os tipos de configurações de servidor e estrutura.

Uma estrutura experimental de marés foi criada para desenvolver e testar componentes.

Ferramentas de linha de comando


Para ferramentas de linha de comando, era necessário combinar pequenas bibliotecas de baixo nível em abstrações de nível superior e polir algumas ferramentas existentes.

Para alguns scripts, o bash é ideal. Por exemplo, simplesmente invocar outras ferramentas de shell e passar dados entre elas.

Mas o Rust é uma ótima opção para muitas outras ferramentas. Por exemplo, se você criar uma ferramenta complexa como ripgrep ou uma ferramenta CLI sobre a funcionalidade de uma biblioteca existente.

O Rust não requer um tempo de execução e é compilado em um único binário estático, o que simplifica a distribuição do programa. E você obtém abstrações de alto nível que não estão em outros idiomas, como C e C ++.

O que mais pode melhorar a ferrugem? Claro, abstrações de um nível ainda mais alto.

Com abstrações de nível superior, uma CLI pronta é montada rápida e facilmente.

Um exemplo dessa abstração é a biblioteca de pânico humano . Na ausência dessa biblioteca, no caso de uma falha, o código da CLI provavelmente retornará todo o retorno. Mas não é muito interessante para os usuários. Você pode adicionar tratamento de erros personalizado, mas é difícil.

Com a biblioteca de pânico humano, a saída irá automaticamente para o arquivo de despejo de erro. O usuário verá uma mensagem informativa oferecendo a relatar um problema e fazer o download do arquivo de despejo.



Começar a desenvolver ferramentas CLI também se tornou mais fácil. Por exemplo, a biblioteca confy automatiza sua configuração. Ele pede apenas duas coisas:

  • Qual é o nome do aplicativo?
  • Quais parâmetros de configuração você deseja fornecer (que você define como uma estrutura que pode ser serializada e desserializada)?

O Confy determinará tudo o mais por si próprio.

O que vem a seguir?


Abstraímos muitas tarefas para a CLI. Mas há algo mais a abstrair. Vamos lançar mais bibliotecas de alto nível.

Ferramentas de ferrugem




Ao escrever em qualquer idioma, você trabalha com suas ferramentas: começando com o editor e continuando com outras ferramentas em todos os estágios de desenvolvimento e suporte.

Isso significa que uma linguagem eficaz depende de ferramentas eficazes.

Aqui estão algumas novas ferramentas (e melhorias nas já existentes) no Rust 2018.

Suporte IDE


Obviamente, o desempenho depende da transferência rápida e suave de código da mente do desenvolvedor para a tela do computador. É aqui que o suporte ao IDE é crucial. Para fazer isso, precisamos de ferramentas que possam "explicar" o IDE para o significado do código Rust: por exemplo, sugira opções significativas para o preenchimento automático de strings.

No Rust 2018, a comunidade se concentrou nos recursos exigidos pelo IDE. Com o advento do Rust Language Server e do IntelliJ Rust, muitos IDEs agora oferecem suporte total ao Rust.

Compilação mais rápida


Melhorar o desempenho do compilador significa acelerá-lo. Foi o que fizemos.

Anteriormente, quando você compilava o engradado Rust, o compilador recompilava cada arquivo único no engradado. A compilação incremental agora está implementada: ele compila apenas as partes que foram alteradas. Juntamente com outras otimizações, isso tornou o compilador Rust muito mais rápido.

rustfmt


A eficiência também exige que nunca discutamos sobre regras de formatação de código nem corrijamos manualmente os estilos de outras pessoas.

A ferramenta rustfmt ajuda com isso: reformata automaticamente o código de acordo com o estilo padrão (pelo qual a comunidade alcançou consenso ). O Rustfmt garante que todo o código Rust corresponda ao mesmo estilo, como o formato clang para C ++ ou Prettier for JavaScript.

Clippy


Às vezes, é bom ter um consultor experiente por perto, dando conselhos sobre as melhores práticas para escrever código. É isso que Clippy faz: verifica o código enquanto o exibe e sugere idiomas padrão.

ferrugem


Mas se você tiver uma base de código antiga com idiomas desatualizados, verifique e corrija independentemente o código pode ser cansativo. Você só quer que alguém faça correções em toda a base de código.

Nesses casos, o rustfix automatiza o processo. Aplica simultaneamente regras de ferramentas como Clippy e atualiza o código antigo de acordo com os idiomas do Rust 2018.

Alterações no próprio Rust


Mudanças no ecossistema aumentaram significativamente a eficiência da programação. Mas alguns problemas podem ser resolvidos apenas por mudanças no próprio idioma.



Como dissemos na introdução, a maioria das alterações de idioma é totalmente compatível com o código Rust existente. Todas essas mudanças fazem parte do Rust 2018. Mas, como não quebram nada, elas funcionam em qualquer código Rust ... mesmo no antigo.

Vamos dar uma olhada nos recursos importantes adicionados a todas as versões. Veja uma pequena lista de recursos do Rust 2018.

Novos recursos para todas as versões


Aqui está um pequeno exemplo dos novos recursos que são (ou serão) em todas as versões do idioma.

Verificação de empréstimo mais precisa


Uma grande vantagem do Rust é a verificação de empréstimos. Ele garante que o código seja seguro para a memória. Mas esse também é um recurso bastante complicado para iniciantes no Rust.

Parte da dificuldade está em aprender novos conceitos. Mas há outra parte ... O teste de empréstimos às vezes rejeita código que parece funcionar do ponto de vista de um programador que entende completamente o conceito de segurança de memória.


Você não pode emprestar uma variável porque ela já está emprestada

Isso acontece porque o tempo de vida do empréstimo deveria se estender até o final de seu campo - por exemplo, até o final da função em que a variável está localizada.

Isso significa que, mesmo que a variável termine de trabalhar com o valor e não tente mais acessar, outras variáveis ​​ainda terão acesso negado a esse valor até o final da função.

Para corrigir a situação, tornamos a verificação mais inteligente. Agora ela vê quando a variável realmente terminou de usar o valor. Depois disso, ele não bloqueia o uso de dados.



Embora isso esteja disponível apenas no Rust 2018, mas em um futuro próximo a função será adicionada a todas as outras versões. Em breve iremos escrever mais sobre este tópico.

Macros processuais em ferrugem estável


O Rust tinha macros antes do Rust 1.0. Mas no Rust 2018, melhorias sérias foram feitas, por exemplo, macros processuais apareceram. Eles permitem que você adicione sua própria sintaxe ao Rust.

O Rust 2018 oferece dois tipos de macros processuais:

Macros de função


Macros de função permitem criar objetos que se parecem com chamadas de função normais, mas são realmente executados em tempo de compilação. Eles pegam um código e distribuem outro, que o compilador insere no binário.

Eles existiam antes, mas com limitações. Uma macro só pode executar a instrução de correspondência. Ele não teve acesso para visualizar todos os tokens no código recebido.

Mas com macros procedurais, você obtém a mesma entrada que o analisador: o mesmo fluxo de tokens. Isso significa que você pode criar macros muito mais poderosas, como funções.

Macros semelhantes a atributos


Se você estiver familiarizado com decoradores em idiomas como JavaScript, as macros de atributo são muito semelhantes. Eles permitem que você anote fragmentos do código Rust que devem ser pré-processados ​​e transformados em outra coisa.

A macro derive faz exatamente isso. Quando você a coloca sobre uma estrutura, o compilador pega essa estrutura (depois de analisada como uma lista de tokens) e a processa. Em particular, ele adiciona uma implementação básica de funções da característica.

Empréstimos mais ergonômicos nas comparações


Há uma mudança simples.

Antes, se você queria emprestar algo e tentava fazer a correspondência, era necessário adicionar uma sintaxe estranha:



Agora, em vez de &Some(ref s) simplesmente escrevemos Some(s) .

Novos recursos do Rust 2018


A menor parte do Rust 2018 é de recursos específicos para esta versão. Aqui está um pequeno conjunto de mudanças no Rust 2018.

Palavras-chave


O Rust 2018 adicionou algumas palavras-chave:

  • try
  • async/await

Esses recursos ainda não foram totalmente implementados, mas as palavras-chave foram adicionadas no Rust 1.31. Portanto, no futuro, não precisaremos introduzir novas palavras-chave (o que se tornaria uma alteração incompatível) quando implementarmos essas funções.

Sistema modular


Uma grande dor para os novatos no Rust é o sistema modular. E está claro o porquê. Era difícil entender por que Rust escolhe um módulo específico. Para corrigir isso, fizemos algumas alterações no mecanismo do caminho.

Por exemplo, se você importou um rack, poderá usá-lo no caminho no nível superior. Mas se você mover qualquer código para um submódulo, ele não funcionará mais.

 // 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 { ... } } 

Outro exemplo é o prefixo ::, usado tanto para a raiz da caixa como para a caixa externa. É difícil entender o que está diante de nós.

Tornamos isso mais explícito. Agora, se você quiser consultar a caixa raiz, use o prefixo crate::. Esta é apenas uma das melhorias para maior clareza.

Se você deseja que o código atual use os recursos do Rust 2018, provavelmente, será necessário atualizar o código para levar em conta novos caminhos. Mas não é necessário fazer isso manualmente. Antes de adicionar o especificador de versão ao Cargo.toml, basta executá-lo cargo fixe rustfixfazer as alterações necessárias.

Informações Adicionais


Todas as informações sobre a nova versão do idioma estão contidas no Guia Rust 2018 .

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


All Articles