Article image
Franklyn Sancho
Franklyn Sancho06/06/2023 18:16
Share

Como construir um simulador de vending machine em Rust com teste unitário

    Resumo

    Se você já tem conhecimento da linguagem rust, talvez um projeto como uma vending machine não seja para você. No entanto, para aqueles que estão dando seus primeiros passos, esta é uma oportunidade de ser apresentado a estrutura e sintaxe. Embora seja um projeto simples, acredito já ser capaz de apresentar muitas coisas.

    Por fim, vamos criar um simulador de vending machine, aquelas máquinas que encontramos em aeroportos e outros estabelecimentos, onde podemos inserir uma moeda e comprar doces, refrigerantes, salgadinhos e etc.

    image

    Instalação e configuração

    Para verificar se você já tem o rust instalado na sua máquina é muito simples, basta rodar no seu terminal o seguinte comando

    rustc --version 
    

    Se retornar a versão do seu rust, significa que já está instalado, caso contrário, o terminal não reconhece o comando. Caso não esteja instalado, basta seguir os passos dessa página - oficial da linguagem:

    https://www.rust-lang.org/pt-BR/tools/install

    após a instalação, basta criar um diretório no lugar desejado - eu vou criar na minha pasta de projetos localizada em meus documentos - eu vou chamá-lo de vending_machine. Para criar o diretório e configurar o ambiente, basta entrar com esses comandos via terminal, mas você pode fazer de forma manual também

    LINUX e WINDOWS
    $ mkdir vending_machine //comando cria o diretório 
    $ cd vending_machine //acessamos o direrótio
    $ cargo init 
    

    O cargo é o gerenciador de pacotes do rust, por meio dele podemos instalar pacotes e dependências em nossa aplicação - se vocês já desenvolveram em NodeJS, o comando cargo init seria como o npm init - ele cria três arquivos, o Cargo.toml, o main.rs e o Cargo.lock - o único que precisamos nos preocupar nesse momento é o main.rs

    Pronto! o ambiente já está configurado e podemos dar inicio ao desenvolvimento:

    Importações e structs

    A primeira coisa que precisamos fazer é definir as importações e estruturas.

    Se estamos construindo uma vending_machine em CLI, ou seja, que vai rodar diretamente no terminal, precisamos que o usuário seja capaz de inserir moedas e comprar produtos.

    Para que isso seja possível, precisamos importar o io da biblioteca std, que nos permite trabalhar com valores de entrada e saída. Para importar é muito simples, basta ir até o arquivo main.rs e adicionar no topo do código a seguinte estrutura:

    image

    Se vocês já desenvolveram em C++, até aqui não há nenhum mistério.

    As structs

    As structs são encontradas em diversas linguagens de programação, são tipos de dados que agrupam valores relacionados. Ficou muito abstrato? Vamos construir as structs do nosso programa e explicar uma a uma de forma visual:

    image

    1. Temos a struct Produto que recebe dois campos, name, onde adicionamos o nome do produto, e value, onde adicionamos o preço desse produto.
    2. Temos a struct Saldo que recebe o saldo, onde teremos o saldo total adicionado, o campo produtos, onde adicionamos um array de objetos contendo os produtos, e coins, onde adicionamos os valores para inserir.

    Existem muitas formas de desenvolver essa aplicação, poderíamos separar tudo o que tem a ver com produto e saldo em suas respectivas structs, mas dessa forma o programa vai funcionar também

    A Impl

    Vejamos o que a documentação do rust fala sobre as impl - implementações:

    "Methods (métodos) são semelhantes às funções: eles são declarados com a chave fn e o seu nome, eles podem ter parâmetros e valor de retorno, e eles contêm algum código que é executado quando eles são chamados de algum outro lugar. No entanto, métodos são diferentes das funções, porque são definidos no contexto de uma struct"

    Ou seja, se estamos trabalhando com structs, precisamos definir uma implementação - é importante mencionar que a impl precisa ter o nome da struct. Vejamos como vai ficar o inicio do nosso método:

    image

    • A vantagem de se trabalhar com "um vetor de objetos" é que ele facilita a manutenção caso precise adicionar mais produtos ou moedas futuramente.
    • Por exemplo, vamos supor que queiramos adicionar pipoca em nossa máquina, basta instanciar um novo Produto com o nome pipoca e o valor desejado;

    Com a estrutura do nosso implemente construído, podemos adicionar os métodos para a manipulação desses valores.

    Os métodos de TESTE do impl.

    Ao invés de criarmos um menu onde o usuário teria que escolher entre adicionar moedas ou comprar produtos, vamos criar um único input onde o programa vai identificar se é um produto ou uma moeda e executar as funções necessárias.

    Os primeiros métodos que vamos construir será para testar esses valores, ou seja, verificar e testar se é um produto ou uma moeda. Dentro do impl, adicione esses dois métodos de teste, um para a moeda e o outro para produto:

    image

    • Um detalhe importante é que todos os métodos do impl tem como primeiro parâmetro o self - semelhante ao this, quando instanciamos um objeto da classe.

    Os métodos de manipulação do impl.

    Com os nossos métodos de teste feitos, precisamos desenvolver os métodos para adicionar as moedas e comprar produtos. O primeiro que vamos construir será o de adicionar moeda e somar no saldo.

    Lembre-se de que esses métodos precisam estar dentro do escopo do impl Saldo:

    image

    • O método soma o valor inserido no total do saldo. Sempre que o usuário adicionar uma moeda, o método soma o valor no saldo total.
    • Caso o valor não esteja contido na instância coins, o valor retorna um erro de valor inválido.

    O método de comprar um produto terá algumas novidades sobre a linguagem, como o uso do operador match e etc:

    image

    • O método verifica se o valor digitado esta contido no vetor, se verdadeiro, o operador match executa a estrutura com a condição de saldo total e valor do produto.
    • Caso o produto não esteja contigo, é retornado uma mensagem de erro;

    Função Main

    Será por meio da função main onde vamos adicionar o input e construir as ordens da nossa aplicação. A primeira coisa que precisamos fazer é criar uma nova instância saldo e criar um loop, vejamos abaixo:

    image

    A principio, só temos uma nova instância item e um escopo do loop - a ideia é que o nosso programa continue rodando, enquanto o usuário estiver adicionando as moedas e comprando os produtos.

    O input de entrada

    Precisamos construir o input de entrada do nosso usuário, onde ele vai adicionar as moedas ou comprar os produtos. Geralmente, os programas em rust tem uma estrutura muito semelhante para esse recurso, vejamos:

    image

    Agora só falta criar as regras e as condições para que o nosso programe rode de forma correta. Veja como vai ficar a nossa estrutura:

    image

    A função main completa ficará dessa forma:

    image

    Compilando e testando

    Para compilar o programa é muito fácil, basta rodar o seguinte comando no diretório raiz do projeto:

    $ cargo run
    

    O inicio do programa:

    image

    adicionando moeda válidas e inválidas:

    image

    comprando um produto:

    image

    BÔNUS: TESTES

    Funcionar no seu computador não significa que o código esteja funcionando

    Este é o motivo do porque precisamos testar os nossos códigos! o rust possui uma excelente ferramenta nativa e capaz de fazer alguns testes bem interessantes. Para isso, na pasta src, crie um arquivo chamado tests.rs com a seguinte estrutura:

    image

    Agora precisamos criar os testes para comprar produto, para isso, basta adicionar abaixo da função test_add_coins() a seguinte estrutura:

    image

    Como os testes estão em outro arquivo, precisamos fazer com que o main.rs o reconheço. Basta importá-lo no arquivo main.rs da seguinte forma:

    image

    Para fazer os testes é muito simples, basta entrar com o seguinte comando na pasta raiz do projeto:

    $ cargo test
    

    Conclusão

    Com algumas linhas, conseguimos construir um simulador de vending_machine totalmente funcional. Claro, existem muitas formas de construir esse programa, poderíamos ter separado em arquivos ou feito as implementações de saldo e produto separadas, o que seria uma boa prática, mas como estamos lidando com uma aplicação pequena, vi como adequado.

    Mas no próximo artigo nós vamos refatorar esse código, separar os arquivos e deixá-lo mais limpo. Já adianto que o rust não é uma linguagem simples, tem uma estrutura muito semelhante ao C++, mas é maravilhosa para se trabalhar.

    Share
    Comments (1)
    Everton Martins
    Everton Martins - 06/06/2023 19:46

    Muito bom, obrigado por compartilhar o conhecimento.