DEV Community

Cover image for Como o programar em Rust me faz ver a memória de maneira diferente
Gabriel Grubba
Gabriel Grubba

Posted on • Originally published at blog-grubba.vercel.app

Como o programar em Rust me faz ver a memória de maneira diferente

Rust

O que é o Rust

O Rust é uma linguagem compilada (similar ao C e C++) com o foco de ser concorrente e memory safe, o que é extremamente útil em sistemas onde performance é o que importa. Porém por ser uma linguagem moderna, ela possui algumas facilidades que a tornam maravilhosa, como o seu compilador que tem sempre me ajudado, segue um exemplo que eu vi ele me ajudando como se fosse o resultado de um teste unitário

Compiler err code

um exemplo de erro do compilador para mostrar como ele é elegante e extremamente prestativo

Testes ?

Em rust possui por padrão testes e o cargo que é o gerenciador de dependências da linguagem. Falarei hoje mais sobre os testes e como são de facil criação e entendimento. Com uma bela documentação o rust não deixa a desejar em nada nesse ponto.

exemplo de código de testes, observe que possui o código #[test] que mostra qual função pode ser usada pra teste. ele espera um retorno para ser true ou false e baseado nele ele passa. o assert_eq! consegue aceitar uma string como seus parametros onde vc pode explicar melhor o teste

    #[test]
    fn abstract_factory_create_car() {
        let car: Box<dyn Vehicle> = factory_method::ShapeFactory::new_vehicle(&VehicleTypes::Car);
        let result: &str = car.translocate();
        assert_eq!(result, "Moved in land", "Creating a car with a type only ");
    }

    #[test]
    fn abstract_factory_create_boat() {
        let boat: Box<dyn Vehicle> = factory_method::ShapeFactory::new_vehicle(&VehicleTypes::Boat);
        let result: &str = boat.translocate();
        assert_eq!(result, "Moved in water", "Creating a boat with a type only ");
    }

    #[test]
    fn abstract_factory_create_plane() {
        let plane: Box<dyn Vehicle> = factory_method::ShapeFactory::new_vehicle(&VehicleTypes::Plane);
        let result: &str = plane.translocate();
        assert_eq!(result, "Moved in air", "Creating a plane with a type only ");
    }
Enter fullscreen mode Exit fullscreen mode

Tem tipos ?

Temos tipos e ponteiros, o que torna ela extremamente expressiva, posso criar meus tipos como ali em Vehicle mas também posso usar tipos da linguagem como em result que eu uso a referencia de um str que é um pedaço de String como no caso " moved in alguma coisa"

Referencia ?

Como uma lang de baixo nível, temos alguns poderes e uma particularidade da linguagem que é maravilhoso. O conceito de References e Borrowing link, esse conceito é extremamente interessante e elegante de se saber. Se você passar uma variável como argumento em uma função, você perdeu a ownership(posse) da variável, o compilador fala a seguinte frase quando você tenta usar ela novamente:

Another compiler error

Valor já foi movido aqui se você quiser passar de novo você pode passar a referencia dela e alterar os tipos para que isso seja suportado

Como trabalhar com Borrowing ?

Você em rust, pode passar para uma função ao invés de uma variável e mover ela, como o compilador chama, você pode passar a referencia dela e trabalhar lá com ela, mas nunca mutando ou alterando o valor. Sim existe mutabilidade mas você precisa dizer que algo é mutável com a key word mut

Padrões ?

Rust é uma lang com forte inspiração funcional, possui imutabilidade, pattern match e outros traços de linguagens funcionais. Possui contudo modernidades de programação orientada a objetos como traits e strucs e um código muito legível quando procedural

#[derive(Debug)]
pub struct Unique {
    pub global_const: String,
}

/// Get the singleton that is only once initialized
pub fn get_singleton() -> &'static Mutex<Unique> {
    static mut UNIQ: MaybeUninit<Mutex<Unique>> = MaybeUninit::uninit();
    static ONCE: Once = Once::new();
    ONCE.call_once(|| unsafe {
        UNIQ.as_mut_ptr().write(Mutex::new(Unique {
            global_const: "Global string".to_string(),
        }));
    });

    unsafe { &*UNIQ.as_ptr() }
}

pub fn set_singleton(value: &str, singleton_instance: &Mutex<Unique>) {
    let mut new_value = singleton_instance.lock().unwrap();
    new_value.global_const = value.to_string();
}
Enter fullscreen mode Exit fullscreen mode

o Pattern Singleton

use crate::creational::factory_method::VehicleTypes::{Car as CarType, Plane as PlaneType, Boat as BoatType};

pub trait Vehicle {
    fn translocate(&self) -> &str;
}

pub enum VehicleTypes {
    Car,
    Boat,
    Plane,
}

struct Car {}

impl Vehicle for Car {
    fn translocate(&self) -> &str {
        println!("Moved in land");
        "Moved in land"
    }
}


struct Boat {}

impl Vehicle for Boat {
    fn translocate(&self) -> &str {
        println!("Moved in water");
        "Moved in water"
    }
}

struct Plane {}

impl Vehicle for Plane {
    fn translocate(&self) -> &str {
        println!("Moved in air");
        "Moved in air"
    }
}

pub struct ShapeFactory;

impl ShapeFactory {
    pub fn new_vehicle(v: &VehicleTypes) -> Box<dyn Vehicle> {
        match v {
            VehicleTypes::Car => Box::new(Car {}),
            VehicleTypes::Boat => Box::new(Boat {}),
            VehicleTypes::Plane => Box::new(Plane {}),
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

O Pattern de factory

Mais exemplos ?

Por fim gostaria de deixar um exemplo de código que vi na leet code onde pode ser util por mostrar alguns detalhes bem legais da lang que mesmo de baixo nível trabalha com a facilidade que linguagens como o java fariam

    /// given a list of lists which of the list is the biggest sum
    /// as the result of the table!
    ///
    /// _Table_
    /// 
    ///
    /// | Values |   Sum     | Result|  Winner|
    /// |--------|-----------|-------|--------|
    /// | 1 2 3  | 1 + 2 + 3 |  6    |        |
    /// | 5 5 5  | 5 + 5 + 5 |  15   |   X    |
    /// | 3 1 4  | 3 + 1 + 4 |  8    |        |
    /// 
    pub fn biggest_sum(res_: Vec<Vec<i32>>) -> i32 {
        res_.iter()
            .map(|x| x.iter().sum())
            .max()
            .unwrap()
    }

// Teste da função acima
    #[test]
    pub fn biggest_sum_test() {
        let v1 = vec![1, 2 ,3];
        let v2 = vec![5, 5 ,5];
        let v3 = vec![3, 1 ,4];
        let big_vec = vec![v1, v2, v3,];
        let result = biggest_sum(big_vec);

        assert_eq!(result, 15, "Testing sum, should return always 15");
    }
Enter fullscreen mode Exit fullscreen mode

Problema da leet code

Sim, funções terminadas em !(não ele não está falando em voz alta) são macros e isso é um detalhe para outro dia mas que me faz muito feliz. Podemos criar nossos próprios macros que representam funções complexas como o vec![1,2,3] é igual ao Vec::from([1,2,3]), uma maneira mais fácil de inicializar link

Top comments (0)