From cb179a494674a0a24d6dab698f1a28845d57fc31 Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Wed, 25 Sep 2019 13:05:22 -0300 Subject: [PATCH] And that is it for the Rust presentation --- .../porque-voce-deve-aprender-rust/index.md | 235 ++++++++++++++++-- .../rust-issues.png | Bin 0 -> 18314 bytes 2 files changed, 215 insertions(+), 20 deletions(-) create mode 100644 content/presentations/porque-voce-deve-aprender-rust/rust-issues.png diff --git a/content/presentations/porque-voce-deve-aprender-rust/index.md b/content/presentations/porque-voce-deve-aprender-rust/index.md index e156511..f78bdd7 100644 --- a/content/presentations/porque-voce-deve-aprender-rust/index.md +++ b/content/presentations/porque-voce-deve-aprender-rust/index.md @@ -1,6 +1,6 @@ +++ title = "Porque Você Deve Aprender Rust" -date = 2019-09-10 +date = 2019-09-25 [taxonomies] tags = ["pt-br", "rust", "companion post"] @@ -187,6 +187,12 @@ exclamação é colocada para diferenciar de funções normais (no caso, o `println!` vai ser expandido pelo compilador por um conjunto maior de comandos). +{% note() %} +Quem já brincou com `#define`s em C deve saber que não existe nada que indique +o que foi digitado é uma função mesmo ou um `#define` que vai ser expandido em +várias outras funções; Rust não deixa isso acontecer. +{% end %} + Outra coisa a notar é que não estamos definindo o tipo de variável que `a` é. Rust é uma linguagem fortemente e estaticamente tipada. O que está acontecendo é que estamos deixando o compilador inferir qual o tipo que `a` deve ter -- e @@ -194,12 +200,6 @@ por ser um inteiro, provavelmente vai ser um u32 ou u64, dependendo da arquitetura, pois para desambiguação, Rust usa o tipo que gere um código mais rápido, mesmo que ocupe mais memória. -{% note() %} -Quem já brincou com `#define`s em C deve saber que não existe nada que indique -o que foi digitado é uma função mesmo ou um `#define` que vai ser expandido em -várias outras funções; Rust não deixa isso acontecer. -{% end %} - E esse código Rust não compila. Se vocês tentarem compilar esse código, vocês verão a seguinte mensagem de @@ -643,10 +643,9 @@ pode explodir", e não que alguma coisa em tempo de execução vai derrubar a aplicação. E a palavra chave aqui é "explicitamente"; alguém pode considerar que não tratar o `null` do `fopen` também é uma forma de deixar um "aqui a aplicação pode explodir", mas não foi o compilador que deixou isso acontecer; -sempre que pode, ele tentou me impedir de fazer burrada. +sempre que pode, o compilador do Rust tentou me impedir de fazer burrada. -Outra forma de lidar com `Result` é o operador `?`: esse operador só funciona -em funções que também tem um retorno do tipo `Result`; o que ela faz é que +Outra forma de lidar com `Result` é o operador `?`: o que ela faz é que caso a chamada de função retorne um `Err`, esse `Err` é passado como retorno da função com o operador; se a função retornar um `Ok`, então o valor encapsulado é retornado diretamente. Mais uma vez no nosso exemplo da escrita @@ -658,8 +657,9 @@ file.write(b"Hello world")?; OK(()) ``` -O que acontece é que agora essas três linhas _tem_ que estar dentro uma função -com um `Result`. +Como o operador vai fazer com que a função em que essas linhas estão retornem +o `Err` se a chamada falhar, essas três linhas _tem_ que estar dentro uma +função que retorne um `Result`. "Ah, barbada", você pensa, "vou botar `?` em tudo e nunca lidar com o erro". Bom, sim, é uma opção, mas existe uma função que não se pode ter `Result`: a @@ -702,9 +702,7 @@ let presente = Gift { package_color: "red", content: "A GIFT!" }; Eu normalmente não comento isso nas apresentações que eu faço, mas é possível criar uma estrutura do tipo -```rust -struct Gift(String); -``` +`struct Gift(String);` Essa estrutura tem os campos com nomes anônimos e temos que acessar com `.0` ou `.1` (se tiver um segundo campo nessa estrutura) e assim por diante. @@ -715,7 +713,7 @@ usaria algo do tipo. Outro exemplo, que talvez fique mais claro: -```rust +``` struct Celcius(f32); struct Farenheit(f32); ``` @@ -777,7 +775,7 @@ diferentes -- `Ok` pode ter um tipo `T`, enquanto `Err` tem um tipo qualquer tivéssemos: ```rust -enum Result { +enum Result { Ok(T), Err(T) } @@ -817,7 +815,7 @@ utilizando-se traits: ```rust trait Summary { - fn summarize(&self) -> String; + fn summarize(&self) -> String; } ``` @@ -832,7 +830,7 @@ struct Phrase { } impl Summary for Phrase { - fn summarize(&self) -> String { + fn summarize(&self) -> String { self.phrase .split_whitespace() .map(|word| word.chars().nth(0).unwrap()) @@ -866,7 +864,7 @@ Traits funcionam com Generics, e assim podemos forçar a receber estruturas/enums que tenham certas características, como em: ```rust -fn get_summary<T>(summarizable: T) -> String +fn get_summary(summarizable: T) -> String where T: Summary { ... @@ -886,3 +884,200 @@ impl Summary for String { ... } ``` ## Motivo 8: Cargo + +[Cargo](https://doc.rust-lang.org/cargo/) é o gerenciador de pacotes e +dependências do Rust. Ele também serve como gerenciador de projetos e +frontend para outras funcionalidades, como executar testes. + +Cargo é interessante porque faz parte do pacote principal do Rust -- em outras +palavras, a linguagem já vem com um eco-sistema completo. + + +## Motivo 9: Testes + +Rust já vem com testes integrados -- e, como comentado no motivo anterior, +Cargo serve como facilitador para a execução dos testes. + +Por exemplo, o seguinte código mostra um teste em Rust: + +```rust +#[cfg(test)] +mod tests { + #[test] + fn testing() { + assert!(1 == 1); + } +} +``` + +Esse teste não precisa estar num arquivo específico (mas ajuda se você coloca +num arquivo específico); ele não precisa estar em um módulo específico (ou +seja, aquele `mod tests` não necessariamente precisa existir ou mesmo se +chamar `tests`); e as funções não precisam começar com um nome específico. +Tudo que você precisa é definir que o código somente vai existir na +configuração de testes (`#[cfg(test)]`) e marcar cada função que deve ser +chamada durante os testes (`#[test]`). + +Para ver os resultados do teste: + +``` +$ cargo test + Compiling adder v0.1.0 (file:///projects/adder) + Finished dev [unoptimized + debuginfo] target(s) in 0.22 secs + Running target/debug/deps/adder-ce99bcc2479f4607 + +running 1 test +test tests::testing ... ok +``` + +Ao executar `cargo test`, todos os arquivos marcados com testes são compilados +(porque o cargo já ativou a configuração de testes e os blocos marcados são +finalmente adicionados) e executa os testes, mostrando o resultado de cada um. +Não é preciso uma biblioteca externa ou comandos a mais para escrever um +teste. + +{% note() %} +Uma coisa curiosa sobre o `cargo test` é que ele também sai executando tudo +que estiver no diretório `examples`, que normalmente contém exemplos de como +uma biblioteca funciona. + +A parte interessante sobre isso é que durante a execução de testes de várias +bibliotecas, também é validado se os exemplos estão corretos. +{% end %} + +## Motivo 10: Macros + +Macros são uma ferramenta poderosa mas realmente complexa do Rust. Tão +complexa que eu não cheguei a me aprofundar muito, mas como exemplo, deixem-me +mostrar uma biblioteca do Rust, chamada +[Log-Derive](https://docs.rs/log-derive/): + +```rust +#[logfn(ok = "TRACE", err = "ERROR")] +fn call_isan(num: &str) -> Result { + if num.len() >= 10 && num.len() <= 15 { + Ok(Success) + } else { + Err(Error) + } +} +``` + +A parte da macro está no começo da função, no `#[logfn(ok = "TRACE", err = +"ERROR")]`; o que ela indica é que se a função terminar com o status de `Ok`, +deve ser gerado um log no nível "TRACE" (abaixo de "DEBUG") e se a função sair +com status de `Err`, deve ser gerado um log no nível de "ERROR". + +E aí eu pergunto: Você consegue ver alguma linha de log no código da função? +Isso é porque a macro do Log-Derive consegue acessar o código em tempo de +compilação e adicionar/alterar certas construções. + +{% note() %} +Na verdade, eu sei que existem três tipos diferentes de macros em Rust: + +1. Macros mais simples, como a `println!`, que se expandem para uma combinação + maior de comandos (`println!` expande para a aquisição do lock da escrita + padrão -- stdout -- envio dos dados para a saída e liberação do lock, mas + você nunca teve que escrever tudo isso por conta); +2. Macros de implementação de funções em estruturas, que basicamente fazem a + geração de funções como vimos com `impl`; +3. E macros como a Log-Derive, que tem acesso aos tokens que formam o código + fonte e geram uma saída de tokens novamente -- e aí podem adicionar, + remover ou alterar tokens do jeito que quiserem. +{% end %} + +## Motivo 11: Motivos Malucos + +[How Rust’s standard library was vulnerable for years and nobody +noticed](https://medium.com/@shnatsel/how-rusts-standard-library-was-vulnerable-for-years-and-nobody-noticed-aebf0503c3d6): +Nesse artigo de 2018, Sergey Davidoff conta que achou uma falha de segurança +em uma das funções do Rust, mas devido a forma como a mesma deveria ser +chamada, era basicamente impossível de exploitar a mesma. + +[No, the problem isn’t “bad +coders”](https://medium.com/@sgrif/no-the-problem-isnt-bad-coders-ed4347810270): +Esse artigo é uma resposta para as respostas de um artigo da Microsoft, em que +eles reportam que 70% de todos os crashes das aplicações no Windows se devem +ao acesso inválido de memória. Sean Griffin, criador da biblioteca +[Diesel](https://diesel.rs/), que serve para escrever ORMs em Rust, conta que +estava trabalhando em compartilhar uma conexão do PostgreSQL entre várias +threads, e o compilador não deixou. Quando foi examinar exatamente o porque, +percebeu que realmente o que ele queria fazer poderia levar a um acesso +inválido. E Griffin tem experiência de sobra nesse campo, já que também é o +criador do Active Record do Rails. + +Outra coisa maluca: + +![Screenshot do Github do Rust](rust-issues.png) + +A parte que vocês devem estar estranhando é a quantidade de issues que a +linguagem tem (algumas vezes o Github chega simplesmente a mostrar "5000+", +indicado que existem mais de 5000 issues abertas). + +Como pode uma linguagem com apenas 4 anos de existência pública ter mais de +5000 issues abertas? O que acontece é que todo o processo de decisão da +linguagem passa pelo Github: Quando os desenvolvedores do core da linguagem +acreditam que uma funcionalidade deva ser adicionada (ou removida), o que eles +fazem é abrir uma issue no Github para discutir com a comunidade o que e como +isso deve ser feito. + +Lembram que eu comentei que as questões de mensagens de erro não claras podem +(e devem) ser comunicadas para os desenvolvedores? Isso é feito pelo Github. + +Ainda, existem "Working Groups", grupos especializados sobre discussões em +alguns tópicos. Por exemplo, existe um working group para Bancos de Dados, +discutindo como a linguagem pode facilitar a criação de conexões com vários +bancos, interfaces padrões para essas conexões e assim por diante; existe um +working group para jogos, para discutir as coisas que tornam a vida de +desenvolvedores de jogos mais fácil. + +{% note() %} +Existia um working group para CLI (command line interface, ou interface de +linha de comando) para discutir como facilitar a vida de desenvolvedores que +querem construir ferramentas de linhas de comando. Uma vez que o grupo +acreditou ter achado a melhor forma, eles publicaram um livro sobre os +achados, decisões e implementações. + +E isso acontece com todos os working groups -- então pode esperar que, se eles +não fizeram ainda, vai sair um livro de como utilizar bancos de dados com Rust +do Database Working Group e um livro de como escrever jogos em Rust pelo Games +Working Group. +{% end %} + +Por último, existe o script [rustup](https://rustup.rs/). Lembram que eu falei +que Rust tem uma cadência de releases de seis em seis semanas? RustUp ajuda a +manter a sua instalação do Rust -- e componentes associados -- em dia. Não só +isso, mas ele permite a instalação de "toolchains" diferentes: Você pode, por +exemplo, instalar o toolchain para a arquitetura +`armv7-unknown-linux-gnueabihf` e, a partir da sua máquina Linux rodando Intel +gerar um executável para arquitetura ARM; ou, ainda, você pode instalar o +toolchain para a arquitetura `wasm32-unknown-unknown` que, na verdade, não é +uma arquitetura, é o gerador para WebAssembly, o que permite que você converta +seu código Rust para WebAssembly (com algumas restrições) -- e, embora seja +possível gerar WebAssembly em outras linguagens como C++ e C#, se você +utilizar Rust, todas as validações de acesso de memória continuam valendo. + +## E agora? + +Bom, se depois de tudo isso você decidir que quer aprender mais sobre Rust, o +que eu posso sugerir é: + +1. Instale o Rust usando o [RustUp](https://rustup.rs). +2. Leia o [Livro do Rust](https://doc.rust-lang.org/book/); o livro que + explica todas as funcionalidades da linguagem está disponível online e é + possível comprar a versão em ePub da No Starch Press (mas não há diferença + entre a versão online e a impressa/ePub). +3. Confira como Rust funciona lendo o [Rust By + Example](https://doc.rust-lang.org/stable/rust-by-example/). Basicamente + tudo que o Livro cobre também está aqui, mas Rust By Example usa uma forma + diferente de explicação, partindo a partir de exemplos para cada ponto. +4. Você pode brincar com Rust no [Rust + Playground](https://play.rust-lang.org/?version=stable), onde é possível + editar, compilar e executar código Rust de dentro do browser. Somente um + número pequeno de bibliotecas está disponível, mas para brincar com Rust + básico é possível usar isso ao invés de instalar a linguagem inteira. +5. Existe um grupo de usuários de Rust no Telegram, o [Rust + Brasil](https://t.me/rustlangbr). Se tiver alguma dúvida, é só ir lá e + perguntar. + +E era isso! diff --git a/content/presentations/porque-voce-deve-aprender-rust/rust-issues.png b/content/presentations/porque-voce-deve-aprender-rust/rust-issues.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2109f843acbf54f33495db75e8b77fab96992b GIT binary patch literal 18314 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 literal 0 HcmV?d00001