RUST – Primeiras Impressões

Introdução

Cada linguagem de programação tem o seu diferencial. Rust definitivamente coloca o termo “diferencial” em outro patamar.

“Rust é uma linguagem de programação multi-paradigma compilada, desenvolvida pela Mozilla Research. É projetada para ser “segura, concorrente e prática”, suportando os estilos puramente funcional, procedural, e orientado a objetos.” — Fonte: Wikipedia

Diferenciais

Rust e C++ estão no mesmo “patamar” de linguagens de desenvolvimento em nível de sistema (system-level development). Embora a sintaxe seja similar — escopo entre chaves, ponto-e-vírgula como final de instrução, etc — elas possuem diferenças significativas em muitos aspectos. Ambas possuem uma curva de aprendizagem “acentuada”, requerem um esforço maior para iniciantes.

Rust foi construído com foco em segurança e desempenho, ele consegue te dar a velocidade de um C++ (ou mais) com um mecanismo de gerenciamento de memória segura e eficiente. A compilação mais restritiva e assertiva consegue proteger melhor a execução, identificando situações que fatalmente resultariam em comportamentos “inesperados”, desde leaks de memória a race-conditions e acessos indevidos de memória. A compilação valida ao máximo o código antes de rodar a aplicação, gerando o executável final.

Em poucas linhas, a implementação da orientação a objetos gira em torno da implementação de métodos em uma estrutura ( similar ao Struct do c++ ), uma variável que é alterada deve ser declarada como mutável dentro de um escopo, mas o que realmente exige um mind-set diferenciado são os comportamentos de escopo e passagem de parâmetros — por default um objeto passado como parâmetro sem ser uma referência  “move” o escopo do objeto para a função. Graças a este comportamento e as declarações envolvidas nas funções e métodos, o compilador consegue “pegar” as situações de uso adversas que causariam problemas em um fonte C++ em tempo de compilação, sem a necessidade de um “garbage”.

Ping-Pong em Rust

Baseado nos exemplos de Ping-Pong em terminal texto usando Java (veja os posts em Java from Scratch), eu montei o mesmo aplicativo em Rust, usando uma implementação básica muti-plataforma de terminal, identificando o numero de linhas e colunas disponível — ao invés de “chumbar” 80×25 ! O fonte “main.rs” ficou assim:

extern crate ctrlc;

use console::Term;
use rand::Rng;
use std::env;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    // Pega os argumentos da linha de comando
    // espera apenas um argumento, numerico, indicando quantas
    // bolinhas o ping-pong deve mostrar
    let args: Vec<String> = env::args().collect();
    let mut maxballs = 1;
    if args.len() > 1 {
        maxballs = args[1]
        .trim()
        .parse()
        .expect("Please type a number for pingpong balls!");
    }

    // Tempo de cada iteração ( 1/4 de segundo )
    let mswait = std::time::Duration::from_millis(250);

    // Cria um terminal nao-bufferizado usando stdout
    let term = Term::stdout();
    let term_features = term.features();

    // Se o console nao tem o comportamento de um "terminal"
    // mostra o tipo do console em uso e finaliza a aplicação
    if !term_features.is_attended() {
        term.write_line(&format!("Terminal family = {:?}", term_features.family()))
        .unwrap();
        panic!("Terminal Features Unattended");
    }

    // Cria uma tupla para armazenar o limite de tela
    let pscreen = (term.size().0 as i32 + 1, term.size().1 as i32 + 1);

    // Cria o vetor com as bolinhas
    let mut balls: Vec<PingPongBall> = Vec::new();
    for _x in 0..maxballs {
        let mut myball = PingPongBall::new();
        // Sorteia a coordenada de tela inicial de cada bolinha
        myball.row = rand::thread_rng().gen_range(0, pscreen.0) + 1;
        myball.col = rand::thread_rng().gen_range(0, pscreen.1) + 1;
        // Acrescenta a bolinha no vetor
        balls.push(myball);
    }

    // Cria uma thread separada usando a implementacao
    // de tratamento de Control+C multi-plataforma
    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();

    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
    })
    .expect("Error setting Ctrl-C handler");

    // Esconde o cursor
    term.hide_cursor().unwrap();

    // Loop de processamento com
    // Tratamento elegante para control+c
    while running.load(Ordering::SeqCst) {
        // itera todas as bolinhas
        for myball in balls.iter_mut() {
            // Apaga a bolinha
            term.move_cursor_to(myball.col as usize, myball.row as usize)
                .unwrap();
            term.write_line(" ").unwrap();
 
            // Move a bolinha
            myball.pingstep(pscreen);
  
            // Desenha a bolinha
            term.move_cursor_to(myball.col as usize, myball.row as usize)
                .unwrap();
            term.write_line("O").unwrap();
        }
        // Espera um pouquinho ...
        thread::sleep(mswait);
    }

    // Ao sair, Mostra o cursor novamente
    term.show_cursor().unwrap();
}

struct PingPongBall {
    row: i32,
    col: i32,
    rowinc: i32,
    colinc: i32,
    step: i32,
    ballsize: i32,
}

impl PingPongBall {
    // Construtor do objeto
    // nomedafuncao(parametros) -> Retorno
    fn new() -> PingPongBall {
        PingPongBall {
            row: 1,
            col: 1,
            rowinc: 1,
            colinc: 1,
            step: 1,
            ballsize: 1,
        }
    }

    // Método para movimentação da bolinha
    // Recebe as coordenadas de tela como uma tupla
    fn pingstep(&mut self, pscreen: (i32, i32)) {
        if self.row + (self.step * self.rowinc) < 1
            || self.row + self.ballsize + (self.step * self.rowinc) >= pscreen.0
        {
            self.rowinc *= -1;
        }
        self.row += self.step * self.rowinc;

        if self.col + (self.step * self.colinc) < 1
            || self.col + self.ballsize + (self.step * self.colinc) >= pscreen.1
        {
            self.colinc *= -1;
        }
        self.col += self.step * self.colinc;
    }
}

Conclusão

Rust é uma linguagem relativamente “nova”, mas definitivamente seus diferenciais são bem atrativos !!! Veja nas referências do post mais informações a respeito !!! Se você gostou e quer saber mais sobre isso, comente no post 😀 E, claro, dê uma pesquisada, já tem bastante informação e exemplos na Internet !!

E, como de costume, desejo a vocês TERABYTES DE SUCESSO !!! 

Referências

 

2 comentários sobre “RUST – Primeiras Impressões

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s