Mas como eu faço um site?
There are slides in English
Thanks to Erich Gubler
Se você nunca ouviu falar de Rust…
Vou contar o que é Rust
Vou contar como eu conheci Rust
E alguns problemas que a linguagem me ajudou a resolver
Mas se você já ouviu falar…
Vou mostrar alguns passos para
seguir aprendendo
Comecei a me envolver com o deploy das aplicações do meu projeto
NPM + Python + Java + Closure Compiler + SCons + RVM…
Eu queria uma maneira simples de executar aplicações
1 arquivo binário e cross-plataforma
"Pra escrever binário tem que ser C?"
Rust foi uma das opções na minha busca por alternativas
"Mas o que é Rust?"
Rust é uma linguagem de programação de sistemas que roda incrivelmente rápido, previne falhas de segmentação, e garante segurança entre threads.
"É uma linguagem bem moderna,
com foco em baixo nível"
Uma linguagem com várias
características funcionais:
O que me chamou atenção para seguir aprendendo:
Todas essas características criam um ambiente ideal para avançar com segurança
Quantas falhas podem acontecer em um programa de baixo nível?
BufferOverflow, Segmentation Fault,
Use After Free…
Rust tem um sistema de tipos que previne diversos erros de gerenciamento de memória, em tempo de compilação
Gerenciamento de memória sem
Garbage Collector
Vamos ver um pouco de Rust
fn main() { let data = vec!(); println!("Data", data); }
error: argument never used --> src/main.rs:3:22 | 3 | println!("Data", data); | ^^^^ error: aborting due to previous error
fn main() { let data = vec!(); println!("Data {}", data); }
error[E0277]: the trait bound `std::vec::Vec<_>: std::fmt::Display` is not satisfied --> src/main.rs:3:25 | |println!("Data {}", data); | ^^^^ `std::vec::Vec<_>` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string | = help: the trait `std::fmt::Display` is not implemented for `std::vec::Vec<_>` = note: required by `std::fmt::Display::fmt` error: aborting due to previous error
^^^^ `std::vec::Vec<_>` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
fn main() { let data = vec!(); println!("Data {:?}", data); }
error[E0282]: type annotations needed --> src/main.rs:2:16 | 2 | let data = vec!(); | ---- ^^^^^^ cannot infer type for `T` | | | consider giving `data` a type | error: aborting due to previous error
error[E0282]: type annotations needed
$ rustc --explain E0282
fn main() { let data : Vec<char> = vec!(); println!("Data {:?}", data); }
Data []
Em resumo, imagine quão complexo um navegador é por trás dos panos?
Existe algum problema neste código?
use std::thread; use std::time::Duration; fn main() { let data = vec!(); thread::spawn(|| { data.push('a'); }); thread::spawn(|| { data.push('b'); }); thread::sleep(Duration::from_millis(50)); println!("Data {:?}", data); }
Depois de vários ciclos de feedback na compilação:
Nosso binário não terá esses problemas!
use std::thread; use std::sync::{Arc, Mutex}; use std::time::Duration; fn main() { let data = Arc::new(Mutex::new(vec!())); let writer = data.clone(); thread::spawn(move || { let lock_result = writer.lock(); match lock_result { Ok(mut locked_writer) => locked_writer.push('a'), Err(_) => panic!("Could not acquire lock a"), } }); let writer = data.clone(); thread::spawn(move || { let mut locked_writer = writer.lock().expect("Could not acquire lock b"); locked_writer.push('b'); }); thread::sleep(Duration::from_millis(50)); println!("Data {:?}", data); }
Que não conseguimos fazer em outras linguagens mais conhecidas
#[derive(Debug)] struct Pedido { id: i32 } fn novo_pedido() -> Pedido { Pedido { id: 1 } } fn enviar_pedido(pedido: Pedido) { // Código que envia o pedido } fn main() { let pedido = novo_pedido(); enviar_pedido(pedido); println!("Dados do pedido: {:?}", pedido); }
error[E0382]: use of moved value: `pedido` --> src/main.rs:18:39 | 16 | enviar_pedido(pedido); | ------ value moved here 17 | 18 | println!("Dados do pedido: {:?}", pedido); | ^^^^^^ value used here after move
Só podemos acessar o pedido antes de enviarmos as informações nesse cenário
E isso é reforçado pelo compilador
#[derive(Debug)] struct Pedido { id: i32 } fn novo_pedido() -> Pedido { Pedido { id: 1 } } fn enviar_pedido(pedido: Pedido) { // Código que envia o pedido } fn main() { let pedido = novo_pedido(); println!("Dados do pedido: {:?}", pedido); enviar_pedido(pedido); }
Dados do pedido: Pedido { id: 1 }
Tipos não conseguem verificar toda a lógica
pub fn super_calculo(x: i32, y: i32) -> i32 { x + y } #[test] fn test_super_calculo() { assert_eq!(3, super_calculo(1, 2)); }
$ cargo test running 1 test test test_super_calculo ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Tentando evitar que exemplos fiquem desatualizados
/// Realiza um grande cálculo que te deixará surpreso /// # Examples /// /// ``` /// use minha_lib::*; /// /// assert_eq!(5, calculo_surpresa(1, 2)); /// ``` pub fn calculo_surpresa(x: i32, y: i32, z: i32) -> i32 { x + y + z }
Exemplos que aparecem na documentação são executados durante os testes
$ cargo test [...] running 1 test test src/lib.rs - calculo_surpresa (line 4) ... FAILED failures: ---- src/lib.rs - calculo_surpresa (line 4) stdout ---- error[E0061]: this function takes 3 parameters but 2 parameters were supplied --> src/lib.rs:5:32 | 5 | assert_eq!(5, calculo_surpresa(1, 2)); | ^^^^ expected 3 parameters
Gerar a documentação do projeto é simples
$ cargo doc --open
É uma ótima evolução para todo o ecossistema de baixo nível
E uma ótima opção para
construir plataformas de alto nível
Essas foram exemplos de possibilidades e potencial da linguagem
Você pode aprender aos poucos, na sua velocidade
E começando com o que você já está acostumado em outras linguagens
Ah, e esse é o mascote, Ferris
(E dá pra costurar um pra você)
Agora, como faço um site?
Siga as instruções no site do Rustup
Esse é o gerenciador de versões do Rust
No final estará disponível:
$ cargo new --bin meu-site-em-rust
$ cargo run Compiling meu-site-em-rust v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 1.54 secs Running `target/debug/meu-site-em-rust` Hello, world!
Vamos criar um arquivo em src/index.html
com seguinte conteúdo
<!doctype html> <html> <head> <meta charset=utf-8> <title>Olá TDC POA 2017</title> </head> <body> <h1>Olá mundo</h1> <marquee>Olá TDC</marquee> </body> </html>
Vamos usar o framework Nickel para nos ajudar
Adicione a dependência no arquivo Cargo.toml
[dependencies] nickel = "0.10.0"
Agora vamos ver um pouco de Rust, aos poucos.
Vamos abrir o arquivo src/main.rs
.
Primeiro, importamos e incluímos algumas referências do framework web.
#[macro_use] extern crate nickel; use nickel::{Nickel, HttpRouter};
Incluímos todo o conteúdo do nosso arquivo HTML em uma constante.
const INDEX: &str = include_str!("index.html");
Criamos um novo servidor Nickel.
let mut server = Nickel::new(); server.get("/", middleware!(INDEX));
Configuramos a porta a partir da variável de ambiente PORT
.
Vamos usar a porta 3000 de fallback.
let port = std::env::var("PORT").unwrap_or("3000".into()); let url = format!("0.0.0.0:{port}", port = port);
Iniciamos o nosso servidor, com uma mensagem caso haja erros.
println!("On {}", url); server.listen(url) .expect("Não conseguimos iniciar o servidor");
No final teremos isso:
#[macro_use] extern crate nickel; use nickel::{Nickel, HttpRouter}; const INDEX: &str = include_str!("index.html"); fn main() { let mut server = Nickel::new(); server.get("/", middleware!(INDEX)); let port = std::env::var("PORT").unwrap_or("3000".into()); let url = format!("0.0.0.0:{port}", port = port); println!("On {}", url); server.listen(url) .expect("Não conseguimos iniciar o servidor"); }
$ cargo build --release
E executar:
$ ./target/release/meu-site-em-rust
On 0.0.0.0:3000
Listening on http://0.0.0.0:3000
Ctrl-C to shutdown server
Você tem um site em Rust.
E tudo em um só binário!
E tem demo no Heroku!
É tão fácil como outras linguagens, mesmo sendo uma linguagem de sistemas
Vou seguir a receita disponível no
$ cargo new --bin minha-chamada-em-rust
$ cargo run Compiling minha-chamada-em-rust v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 1.54 secs Running `target/debug/minha-chamada-em-rust` Hello, world!
Já existem diversas bibliotecas disponíveis no Crates.io
Vamos usar o Reqwest nesse projeto
Adicione a dependência no arquivo Cargo.toml
[dependencies] reqwest = "0.8.0"
Vamos importar a nossa biblioteca e algumas funções de I/O
extern crate reqwest; use std::io::Read;
E criar nossa função
fn main() { let mut response = reqwest::get("https://httpbin.org/get") .expect("Could not connect"); println!("Resposta: {:?}", response); let mut content = String::new(); response.read_to_string(&mut content); println!("Conteudo do site: {}", content); }
Vamos executar!
$ cargo run
Agora você tem um código para fazer chamadas na internet!
Bem similar a outras linguagens?
Eu passei semanas batendo a cabeça em conceitos que eram novos para mim.
lifetime
e borrow
demoraram pra entrar na minha cabeçaRust trouxe novos conceitos para minha caixa de ferramentas.
E eu tenho me divertido muito!
A comunidade é muito aberta e me ajudou bastante, e tem muito interesse em trazer pessoas novas.
Muitas pessoas estão disponíveis para ajudar no #rust-beginners, no fórum e até no #rust-br.
Existe um grande esforço em tornar todo o ecossistema inclusivo, tanto a participação das pessoas quanto material para todos os níveis.
Iniciativa para ensinar Rust para quem não é bem representado na área de tecnologia
Com interesse de tornar a linguagem uma boa primeira linguagem de programação
Todas as propostas de mudança da linguagem seguem um processo de RFC
Que agora requer que novas propostas tenham documentação e uma maneira clara para ensinar a mudança
Eu usei esse buildpack.
Já existem vários frameworks, mas ainda é um ecossistema em desenvolvimento.
Uma boa lista está disponível no site Are We Web Yet?
Confira o Rocket, que usa uma sintaxe mais sucinta…
Mas depende de funcionalidades do compilador ainda em desenvolvimento.
É o método mais recomendado pela comunidade
Rust está disponível nos gerenciadores de pacotes dos sistemas operacionais também, mas pode demorar um pouco mais para receber atualizações.
O Diesel pode ajudar nisso.
Sim. Inclusive o Firefox do seu computador já tem partes em Rust.
Algumas empresas: Dropbox, Chef, Tilde, Sentry, CoreOS, Mozilla e tem mais na lista do site.
Não, dá pra usar para muitos outros lugares!
(Se eu fosse falar todos os exemplos, seria uma outra apresentação inteira)
Dois fortes* espaços para aplicar a linguagem:
Extensões de linguagens (Gems, npm, python extensions, FFI)
*IMHOMachine Learning, Ruby, Python, Haskell, Node.js, WebAssembly, Container, Network Platform, Embedded, Sistemas Operacionais123, Jogos, cross-compilação, CI…
Se você se interessou por Rust, pode entrar em contato comigo também, que eu quero te ajudar com os próximos passos.
Bruno Tavares - @bltavares