No ultimo post sobre Rust, criamos nosso primeiro programa, um incrível 'hello world'

e se vocês repararam, a depender do sistema operacional que estamos utilizando os comandos que temos de rodar para compilar e executar nosso programa a partir do terminal mudam um pouco de acordo com o sistema operacional.
Porém existe uma ferramenta que pode não só solucionar esse problema de discrepância entre sistemas operacionais, como também nos auxiliar em diversas tarefas que são comuns no nosso dia a dia, essa ferramenta se chama Cargo.
A principal função do cargo é gerenciar o uso de dependências no nosso projeto (libs de terceiros que podemos usar no nosso programa), mas você deve estar se perguntando mas porque raios isso é importante? E como o cargo resolve o problema de comandos diferentes para compilar e executar nosso programa em diferentes sistemas operacionais?
Calma vamos ver na pratica um pouco de como o cargo funciona e como ele faz para resolver os problemas citados acima, se você instalou o rust de acordo com os posts anteriores então por tabela o cargo também ja esta instalado no seu PC, portanto abra um terminal/prompt e digite o seguinte comando:

O que fizemos aqui foi criar um novo projeto rust chamado 'rust_which' usando o cargo, aqui o rust ja começa a resolver alguns de nossos problemas pois ele cria toda estrutura básica de pastas e arquivos do nosso programa, bem como não importa a plataforma (Windows, Linux ou Mac) o comando utilizado será o mesmo.
Se entrarmos no diretório `rust_which` que foi criado pelo cargo podemos observar a estrutura de pastas e diretórios criada pelo cargo e olhar mais de perto o que significa cada coisa

Vemos que temos um diretório oculto '.git' e um arquivo oculto '.gitignore' o que significa que o cargo ja iniciou um repositório git para o nosso projeto.
Temos também os arquivos 'Cargo.lock' e 'Cargo.toml' eles são usados pelo cargo para gerenciar as dependências do nosso projeto e veremos mais sobre eles mais adiante nesse post.
O diretório 'src' é onde fica todo nosso código e se dermos uma olhada mais de perto vemos que o cargo ja criou um arquivo main.rs que contem um hello world dentro dessa pasta:

ja a pasta target não nos interessa muito no momento, o cargo guarda dentro dela binários gerados ao compilar nosso código entre outras coisas.
O cargo pode ser usado não só para criar um novo projeto rust como para rodar um projeto existente, para isto dentro da pasta do projeto digite 'cargo run'

Veja que o cargo compilou e executou nosso programa numa tacada só, não precisamos rodar o comando 'rustc' na mão para compilar nosso programa como da ultima vez! E melhor ainda não precisamos rodar o './' (Linux/Mac) ou o '.\' (Windows) para executar o nosso programa pelo terminal, isso significa que não importa qual plataforma estamos utilizando o comando que precisamos para compilar e rodar o nosso programa é sempre o mesmo.
Mas o cargo possui muitos outros comandos alem de 'new' e 'run', como por exemplo comandos para rodar testes, instalar programas rust no nosso pc, checar se o nosso código possui problemas antes de compilar, baixar outros programas feitos em rust, fazer um release do nosso programa e muito mais.
Vamos dar sequencia no desenvolvimento do nosso programa o seu objetivo sera funcionar como o comando 'which' do mundo unix, o 'which' é usado para informar em qual diretório o executavel de um programa que esta no nosso PATH se encontra, por exemplo no Mac/Linux se quisermos descobrir onde o executavel do 'bash' esta podemos digitar o seguinte comando:

com isso sabemos que o executável do 'bash' se encontra dentro do diretório '/bin/'
Sem mais, vamos por a mão na massa, abra o arquivo 'rust_which/Cargo.toml' no seu editor de preferência:

O 'Cargo.toml' é conhecido pelos programadores rust como manifesto, aquilo que esta entre colchetes são as chamadas sessões um manifesto pode possuir uma ou mais sessões no nosso caso o cargo ja criou duas sessões a '[package]' e a '[dependencies]'. tudo que esta abaixo de '[pacakge]' e antes de '[dependencies]' pertence a sessão '[package]', e tudo que esta entre a declaração '[dependencies]' e o fim do arquivo pertence a sessão '[dependencies]', portanto podemos dizer que uma sessão começa logo abaixo de sua declaração e termina quando encontra uma nova declaração de sessão ou no fim do arquivo.
A sessão '[package]' é utilizada para especificar meta dados como nome do projeto, autores, edição do rust que desejamos utilizar, versão e etc.
Ja a sessão '[dependencies]' assim como o nome sugere é onde especificamos dependências externas que desejamos utilizar no nosso projeto, repare que ela se encontra vazia, vamos mudar isso agora abra o arquivo `Cargo.toml` do seu projeto e adicione o seguinte texto:

Para efetivar nossa adição de uma nova dependência podemos dentro da pasta do nosso projeto rodar o comando `cargo build` o qual ira apenas compilar nosso projeto mas não ira executá-lo

Veja que ao rodarmos cargo build pela primeira vez o cargo ira baixar no nosso projeto a lib 'which' e todas suas dependências, e ao rodarmos o comando uma segunda vez o cargo ja sabe que nossas dependências ja estão instaladas sendo assim ele não vai tentar baixar nada, repare também que no arquivo `Cargo.toml` colocamos 'which = "3.0.0"' no entanto conforme é possível observar na figura acima o cargo baixou a versão '3.1.1'. Isso ocorre porque o cargo segue a convenção de versionamento conhecida por Semantic Versioning ou semver para os íntimos, nesse caso ao especificarmos o numero '3.0.0' no 'Cargo.toml' estamos dizendo que queremos qualquer versão da lib que seja >= 3.0.0 e < 4.0.0.
Agora se conferirmos o arquivo `Cargo.lock` veremos que ele não esta vazio, é nesse arquivo que o Cargo controla qual a versão exata das suas dependências, bem como quais são as dependências das dependências e suas respectivas versões, se por exemplo eu disponibilizar o nosso projeto no github e outro programador clonar o projeto e tentar rodar na sua maquina o cargo ira garantir que o projeto use exatamente as mesmas dependências que eu estava usando. Mas muito cuidado o diferente do 'Cargo.toml' o 'Cargo.lock' é um arquivo no qual nós devemos evitar de mexer ou realizar qualquer tipo de alteração manual ele é de uso exclusivo do Cargo.
Agora com nossa dependência instalada, vamos ao nosso arquivo src/main.rs dentro da pasta do nosso projeto e vamos colocar la o seguinte código:
use which::which;
fn main() {
let result = which("rustc");
println!("the path to rustc is {:?}", result);
}
Como a biblioteca which agora esta presente no nosso projeto, nós podemos utiliza-la no nosso projeto mas para tanto primeiro precisamos da instrução 'use which::which' no topo do nosso arquivo o que significa que estamos importando a biblioteca which para dentro do nosso escopo global e portanto acessível para todo nosso programa.
Ja dentro do nossa função 'main' estamos declarando uma variável de nome 'result' que tem como valor o resultado da função 'which("rustc");' essa função ira descobrir o path para o binário 'rustc' caso o mesmo não esteja na sua variável PATH ou não esteja instalado ela ira retornar um erro.
Vamos executar o nosso código usando 'cargo run' para ver se tudo esta ok:

Veja que o programa rodou com sucesso e exibiu nossa mensagem porém a mensagem esta meio estranha

olhem aquele 'Ok("/Users/...")' hmm não colocamos nada disso na nossa mensagem!
Isso ocorre porque em rust existe a pratica de "embrulhar" o resultado de uma operação que pode resultar em erro de forma a evitar que um erro venha a ocorrer sem que tenhamos a oportunidade de trata-lo fazendo com que nosso programa quebre (mais sobre isso no ORUTUF =D) de qualquer forma o que precisamos agora e "desembrulhar" o resultado da função 'which("rustc")', para isso vamos usar a função 'unwrap'
use which::which;
fn main() {
let result = which("rustc").unwrap();
println!("the path to rustc is {:?}", result);
}
ao invés de usarmos o 'cargo run' podemos apenas conferir se nosso programa esta ok sem necessariamente executa-lo com o comando 'cargo check'

Nenhum erro tudo certo! Agora podemos rodar o 'cargo run' e conferir o resultado final.

Ótimo agora a mensagem esta ok.
Apesar de ser um programa que só nos diz o path do binário "rustc" esse pequeno exercício foi o suficiente para vermos o cargo em ação usando os comandos "new", "check" e "run" e fazendo uso dele para adicionar dependências ao nosso projeto.
Porém como bonus vamos ver um ultimo comando interessante 'cargo install'

esse comando ira instalar o nosso humilde programa em nossa maquina e agora podemos executa-lo em qualquer diretório do nosso sistema sem ajuda do cargo como a seguir:

Espero que esse tópico tenha conseguido mostrar um pouco do que o cargo faz e de como ele é util, passamos BEM por cima também de outros assuntos como a função `unwrap()`, semantic versioning, arquivos .toml e claro o próprio cargo possui muito mais funcionalidades mas iremos velas em ação conforme formos avançando na nossa jornada.
sobre SemVer vocês podem ler esse documento:
Versionamento Semântico 2.0.0 | Semantic Versioninge sobre o .toml tem essa pagina no github:
GitHub - toml-lang/toml: Tom's Obvious, Minimal Languagepara entender mais afundo sobre o Cargo.toml e o Cargo.lock veja
Cargo.toml vs Cargo.lock - The Cargo BookVejo vocês no próximo post