Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Menos Teoria, Mais Rust

Rust é famosa por sua velocidade, segurança e prevenção de bugs. Mas por onde começar? O livro oficial é ótimo, mas às vezes queremos apenas ir direto ao ponto.

É por isso que este livro existe.

Ele foi criado para ser sua ponte entre a teoria complexa e o código funcional, facilitando sua introdução à linguagem qualquer que seja seu nível. A abordagem é direta: menos teoria, mais prática.

O que você encontrará aqui:

  • Inúmeros exemplos;
  • Perguntas rápidas de fixação (3 a 5 minutos);
  • Projetos para por a mão na massa;
  • Links com material complementar.

Vamos começar a programar?

"A beleza que vive no ato de compartilhar algo com os outros." Monja Coen

Introdução ao Rust

Rust foi criado por Graydon Hoare na Mozilla Research em 2010. A primeira versão estável, 1.0, foi lançada em 2015, marcando o início de sua popularidade e adoção mais ampla na indústria.

Rust é uma linguagem de código aberto (open-source) e compilada, o que significa que é traduzida diretamente para código de máquina. Isso a torna extremamente rápida, sem a necessidade de um interpretador como Python ou JavaScript. Ela se posiciona como uma alternativa a linguagens como C e C++, que são conhecidas por sua performance, mas também são mais suscetíveis a erros de memória, como null pointers (ponteiros nulos) ou data races (condições de corrida de dados).

A grande inovação do Rust é o Ownership Model (Modelo de Posse), um sistema que garante a segurança de memória em tempo de compilação. Isso significa que o compilador do Rust verifica se o seu código está livre de erros de memória antes mesmo de ser executado. O compilador se torna um "guardião" da memória, e se ele não aprovar o seu código, ele simplesmente não compila. Essa abordagem elimina toda uma classe de bugs que são comuns em outras linguagens.

Começando

Olá, seja bem-vindo!

Este projeto foi criado não apenas para ajudá-lo a aprender a linguagem, mas também como um material de consulta. A longo prazo, este conteúdo será expandido continuamente, até se tornar algo mais completo e abordar de forma simples diversos tópicos complexos que ainda carecem de documentação, principalmente em português.

Espero de coração que você consiga aprender junto comigo e que este material lhe seja tão útil quanto tem sido para mim. Aproveite bem o que foi construído até aqui e continue acompanhando, pois novos conteúdos serão adicionados regularmente.

Bons estudos!

Rust Playground

O Rust Playground é a maneira mais rápida de começar a experimentar com Rust. É um ambiente online onde você pode:

  • Escrever e rodar código Rust diretamente no seu navegador;
  • Testar pequenos exemplos e conceitos;
  • Compartilhar código com outros desenvolvedores;
  • Verificar como o compilador se comporta em diferentes edições do Rust.

Acesse: https://play.rust-lang.org

Instalar

O rustup é o instalador oficial e gerenciador de versões do Rust. Ele permite instalar e atualizar o compilador, o Cargo e outras ferramentas do ecossistema com facilidade.

Para instalar no macOS, Linux ou em outros sistemas operacionais tipo Unix, execute o seguinte em seu terminal e siga as instruções na tela:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Certifique-se de visitar o site oficial do Rust para melhor entender o processo de instalação e outras ferramentas:

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

Se você estiver no Windows, procure por "Outros Métodos de Instalação":

https://forge.rust-lang.org/infra/other-installation-methods.html

Versão

Se você deseja ver a versão do Rust:

rustc --version

Se você deseja ver a versão do Cargo:

cargo --version

Para visualizar informações completas sobre o ambiente Rust instalado, incluindo toolchains ativos e componentes, utilize:

rustup show

Desinstalar

Se em algum momento você quiser desinstalar o Rust, execute:

rustup self uninstall

Atenção: Isso removerá o Rust, o Cargo e todas as ferramentas instaladas via rustup do seu sistema.

Editores e IDEs

A seguir, alguns editores e IDEs recomendados para desenvolvimento em Rust.

Zed

Um editor de código moderno e extremamente rápido, desenvolvido pelos criadores do Atom, focado em desempenho e colaboração em tempo real.

https://zed.dev/

RustRover: IDE Rust da JetBrains

É a IDE dedicada da JetBrains para Rust, oferecendo recursos avançados de desenvolvimento, como depuração inteligente, refactoring (refatoração) e análise de código.

https://www.jetbrains.com/rust/

VS Code: com a extensão rust-analyzer

É uma combinação popular e leve para o desenvolvimento em Rust, oferecendo autocomplete (autocompletar), verificação de erros em tempo real e integração com as ferramentas do ecossistema Rust.

https://code.visualstudio.com/
https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer

Helix

Editor de texto modal moderno inspirado em Vim/Kakoune, com suporte nativo a LSP (Language Server Protocol) e destaque de sintaxe, oferecendo uma experiência de edição rápida e eficiente sem a necessidade de configuração inicial.

https://helix-editor.com/
Config: languages.toml

O arquivo de configuração deve ser colocado em ~/.config/helix/languages.toml.

[[language]]
name = "rust"
auto-format = true

roots = [
  "Cargo.toml",
  "Cargo.lock"
]

[language.auto-pairs]
'(' = ')'
'{' = '}'
'[' = ']'
'"' = '"'
'`' = '`'

[language-server.rust-analyzer]
command = "rust-analyzer"

[language-server.rust-analyzer.config]
inlayHints.bindingModeHints.enable = false
inlayHints.closingBraceHints.minLines = 10
inlayHints.closureReturnTypeHints.enable = "with_block"
inlayHints.discriminantHints.enable = "fieldless"
inlayHints.lifetimeElisionHints.enable = "skip_trivial"
inlayHints.typeHints.hideClosureInitialization = false

Neovim: com plugins específicos para Rust

Evolução moderna do Vim com suporte nativo a LSP, interface assíncrona e extensibilidade via Lua, sendo altamente customizável e ideal para desenvolvedores que buscam um editor modal poderoso e eficiente.

https://neovim.io/
Config:

Entre os plugins mais recomendados para Rust no Neovim estão o rustaceanvim (integração completa com rust-analyzer) e o crates.nvim (gerenciamento de dependências do Cargo diretamente no editor).

Nota: O guia externo abaixo pode ficar desatualizado com o tempo. Prefira consultar a documentação oficial dos plugins para configurações mais recentes.

  https://rsdlt.github.io/posts/rust-nvim-ide-guide-walkthrough-development-debug/

Conceitos Comuns de Programação

Este capítulo foi desenvolvido para apresentar os conceitos fundamentais da linguagem de programação Rust. No entanto, os tópicos abordados aqui também estão presentes em outras linguagens de programação. Se esta é a primeira vez que você se depara com esses conceitos, espero que você possa entender cada ponto claramente, pois isso forma a base essencial para o que virá nos próximos capítulos.

No final, você encontrará alguns exercícios práticos, permitindo que você verifique se perdeu algum conceito durante seus estudos. Mas não se preocupe, as perguntas são objetivas e incluem as respostas.

Comentários

Comentários são usados para documentar seu código, tornando-o mais compreensível para você e outros desenvolvedores. Eles são ignorados pelo compilador, o que significa que não afetam como seu programa é executado, apenas a sua legibilidade.

//

#![allow(unused)]
fn main() {
// Este é um comentário de linha única.
}

/* */

#![allow(unused)]
fn main() {
/*
  ...
  Este é um comentário de múltiplas linhas.
  ...
*/
}

///

#![allow(unused)]
fn main() {
/// Comentários de documentação (doc comments):
///  - Geram documentação automaticamente: cargo doc;
///  - São compatíveis com markdown;
///  - Documentam o item seguinte: função, módulo, struct, etc.
}

Execute cargo doc --open para gerar e abrir a documentação do seu projeto no navegador.

//!

#![allow(unused)]
fn main() {
//! Comentário de documentação interno (inner doc comment):
//!  - Documenta módulos/crates: lib.rs;
//!  - Colocado no início dos arquivos.
}

/* // /**/ */

#![allow(unused)]
fn main() {
/* Comentários aninhados (nested comments):
    // Rust permite comentários dentro do bloco de comentário.
    /* ... */
*/
}

Print

A macro print! e suas variações são usadas para depuração, informar o usuário e gerar saída formatada.

print!

#![allow(unused)]
fn main() {
// imprime o texto sem quebra de linha
print!("Olá,");
print!("mundo!");
print!("...");
}

println!

#![allow(unused)]
fn main() {
// imprime o texto com quebra de linha
println!("Olá,");
println!("mundo!");
println!("...");
}

eprint!

#![allow(unused)]
fn main() {
// imprime o texto de erro sem quebra de linha
eprint!("ERRO:");
eprint!("Falha ao carregar arquivo!");
}

eprintln!

#![allow(unused)]
fn main() {
// imprime o texto de erro com quebra de linha
eprintln!("ERRO:");
eprintln!("Falha ao carregar arquivo!");
}

Em terminais Unix, você pode redirecionar a saída padrão com > e a saída de erro com 2>:

cargo run > saida.txt 2> erros.txt

Caracteres de Escape

São aqueles que começam com \ e são usados para representar caracteres especiais que não podemos (ou não devemos) digitar literalmente no código, como quebras de linha, tabulações, aspas dentro de strings, etc.

\n

#![allow(unused)]
fn main() {
// quebra de linha
println!("Qual é o seu nome?\nMeu nome é Alice!");
}

\'

#![allow(unused)]
fn main() {
// aspas simples
println!("Qual é o seu nome?\'Meu nome é Alice!\'");
}

\"

#![allow(unused)]
fn main() {
// aspas duplas
println!("Qual é o seu nome?\"Meu nome é Alice!\"");
}

\\

#![allow(unused)]
fn main() {
// barra invertida
println!("Qual é o seu nome?\\Meu nome é Alice!\\");
}

\t

#![allow(unused)]
fn main() {
// tabulação horizontal (tab)
println!("Qual é o seu nome?\tMeu nome é\tAlice!");
}

r

#![allow(unused)]
fn main() {
// raw string: trata a barra invertida literalmente, sem processar sequências de escape
println!(r"C:\Users\Alice\Documents");
}

r#...#

#![allow(unused)]
fn main() {
// raw strings (string literal/sem processamento de escape)
println!(r#"
  Qual é o seu nome?
  Meu nome é "Alice!"
"#);
}

\x

#![allow(unused)]
fn main() {
// caractere ASCII de 7 bits - 0x00 e 0x7F
println!("\x53\x6E\x6F\x6F\x70\x79\x21");
}

\u{...}

#![allow(unused)]
fn main() {
// unicode (permite usar emojis ou caracteres especiais)
println!("(\u{25D5}\u{2323}\u{25D5})");
}

\r

#![allow(unused)]
fn main() {
// move o cursor de volta para o início da linha sem avançar para a próxima
print!("Carregando ...\r");
}

Comumente usado para animações de terminal: \r o efeito pode variar conforme o terminal ou sistema operacional.

Variáveis

Variáveis são espaços nomeados na memória que podem armazenar um valor.

#![allow(unused)]
fn main() {
let nome = "Maria";
println!("Qual é o seu nome: {}", nome);
}
#![allow(unused)]
fn main() {
let idade = 29;
println!("Qual sua idade? {}", idade);
}
#![allow(unused)]
fn main() {
let nome = "Maria";
let idade = 29;
println!("{} tem {} anos", nome, idade);
}

Saiba mais sobre variáveis.

Mutabilidade

Uma vez que o valor de uma variável é definido, você não pode alterá-lo posteriormente. No entanto, usar mut após let torna a variável criada mutável.

let mut

#![allow(unused)]
fn main() {
let mut nome = "Miguel";
println!("Qual é o seu nome: {}", nome);

nome = "Sophia";
println!("Qual é o seu nome: {}", nome);
}
#![allow(unused)]
fn main() {
let mut idade: u8 = 87;
println!("Qual sua idade? {}", idade);
 
idade = 49;
println!("Qual sua idade? {}", idade);
}

Constante

A constante é um identificador com valor fixo e imutável, avaliado em tempo de compilação. Por convenção, o nome de constantes em Rust é escrito em SCREAMING_SNAKE_CASE.

const PI: f32 = 3.14159;

fn main () {
    println!("{:.2}", PI);
}
const ERROR_404: &str = "Erro 404";

fn main () {
    println!("{}", ERROR_404);
}

O tópico de tipos de dados será abordado em detalhes no próximo capítulo.

Formatação

A macro format! em Rust é usada para melhorar a formatação da saída de dados, utilizando {} como placeholders (espaços reservados) que serão preenchidos com a informação.

{}

#![allow(unused)]
fn main() {
let nome = "Rafael";
let idade = 12;
println!("Oi, eu sou {}, tenho {} anos", nome, idade);
}
#![allow(unused)]
fn main() {
let nome = "Manuela";
let idade = 37;
println!("Oi, eu sou {nome}, tenho {idade} anos");
}

format!

Sempre retorna uma String com o conteúdo formatado.

#![allow(unused)]
fn main() {
let nome = "Arthur";
let idade = 69;

let texto = format!("Oi, eu sou {}, tenho {} anos", nome, idade);
println!("{}", texto);
}
#![allow(unused)]
fn main() {
let nome = "Charlie Brown";
let idade = 8;

let texto = format!("Eu sou o {nome}, tenho {idade} anos");
println!("{}", texto);
}

Para mais informações: std::fmt

Formatação para Debugging

Em Rust, {:?} e {:#?} são especificadores de formato que utilizam o trait Debug para exibir a representação interna de valores. São especialmente úteis para depuração e inspeção durante o desenvolvimento.

{:?}

#![allow(unused)]
fn main() {
// saída compacta
let pessoa: (&str, u8, f32) = ("Laura", 19, 1.77);
println!("{:?}", pessoa);
}

{:#?}

#![allow(unused)]
fn main() {
// saída mais legível
let pessoa: (&str, u8, f32) = ("Pedro", 90, 1.90);
println!("{:#?}", pessoa);
}

{var:?} ou {var:#?}

#![allow(unused)]
fn main() {
let pessoa: (&str, u8, f32) = ("Violet", 28, 1.58);
println!("{pessoa:?}");
}
#![allow(unused)]
fn main() {
let pessoa: (&str, u8, f32) = ("Violet", 28, 1.58);
println!("{pessoa:#?}");
}

Shadowing (Sombreamento)

Você pode declarar uma nova variável com o mesmo nome de uma variável existente, mas a variável anterior é ocultada (shadowed) pela nova.

#![allow(unused)]
fn main() {
let comida = "Pizza";
println!("{}", comida);

let comida = "Biscoitos";
println!("{}", comida);

let comida = "Sorvete";
println!("{}", comida);
}
#![allow(unused)]
fn main() {
let animal = "Cachorro";
println!("{}", animal);

let animal = "Pássaro";
println!("{}", animal);

let animal = "Gato";
println!("{}", animal);
}
#![allow(unused)]
fn main() {
let numero: i8 = 80;
println!("{}", numero);

let numero: f32 = 2.;
println!("{}", numero);
}

Escopo

Envolver um código entre chaves {} cria um novo escopo (bloco de código) que limita a visibilidade das variáveis definidas dentro dele, logo não pode ser acessada fora daquele bloco.

#![allow(unused)]
fn main() {
let nome = "Aurora";
println!("{}", nome);

{
  let nome = "Ravi";
  println!("{}", nome);
}

println!("{}", nome);
}
#![allow(unused)]
fn main() {
let numero = 40;
println!("{}", numero);

{
  let numero = 0;
  println!("{}", numero);
}

println!("{}", numero);
}

Questões - Conceitos Comuns de Programação


01 - Como você escreveria um comentário de linha única em Rust?

Playground!

Resposta
fn main() {
    // Este é um comentário de linha única    
}

02 - Qual é a sintaxe para comentários de bloco em Rust?

Playground!

Resposta
fn main() {
    /*
      Este é um comentário de
      bloco que abrange várias
      linhas.
    */
}

03 - Você pode aninhar comentários de bloco em Rust? Dê um exemplo.

Playground!

Resposta
fn main() {
    /*
       Início do comentário externo
       /* Este é um comentário de bloco aninhado */
       Fim do comentário externo
    */    
}

04 - Qual macro você usaria para imprimir texto na mesma linha, sem adicionar uma quebra de linha no final?

Playground!

Resposta
fn main() {
    print!("Imprimir sem adicionar uma nova linha no final!");
}

05 - Qual macro você usaria para imprimir texto e adicionar automaticamente uma quebra de linha no final?

Playground!

Resposta
fn main() {
    println!("Imprimir e adicionar nova linha no final!");
}

06 - Escreva um código que imprima "Hello" e "World" na mesma linha usando a macro print!.

Playground!

Resposta
fn main() {
    print!("Hello, ");
    print!("World");
}

07 - Como você insere uma quebra de linha explícita dentro de uma string que está sendo impressa com println!?

Playground!

Resposta
fn main() {
    println!("Primeira linha\nSegunda linha");
}

08 - Que outras sequências de escape você pode usar em strings Rust? Dê exemplos de pelo menos 3.

Playground!

Resposta
fn main() {
    println!("Barra invertida: \\");
    println!("Olá \"mundo\"");
    println!(r"C:\Usuários\Snoopy\Documentos\");
}

09 - Como você declara uma variável chamada score e atribui a ela o valor 100?

Playground!

Resposta
fn main() {
    let score = 100;
    println!("Score: {}", score);
}

10 - Escreva uma linha de código que declare uma variável cidade com o valor Recife e a imprima na tela.

Playground!

Resposta
fn main() {
    let cidade = "Recife";
    println!("Cidade: {}", cidade);
}

11 - O que acontece se você tentar usar uma variável antes de declará-la em Rust?

Playground!

Resposta
fn main() {
    // Isto causaria um erro de tempo de compilação:
    println!("{}", x);
    let x = 5;
} 

12 - Você pode declarar uma variável sem inicializá-la em Rust? Se sim, mostre como usá-la com segurança.

Playground!

Resposta
fn main() {
    let x: i32; 
    x = 42;     
    println!("x = {}", x);
}

13 - Declare uma variável mutável chamada contador inicializada com 0. Em seguida, escreva o código para alterar o valor para 5 e imprima.

Playground!

Resposta
fn main() {
    let mut contador = 0;
    println!("Contador = {}", contador);
    
    contador = 5;
    println!("Contador = {}", contador);
}

14 - O que acontece se você tentar modificar uma variável imutável em Rust?

Playground!

Resposta
fn main() {
    let x = 1;    
    x = 2;
    println!("x = {}", x);
}

15 - Como você declara uma constante chamada MAX_SPEED com o valor "9000" do tipo i32?

Playground!

Resposta
const MAX_SPEED: i32 = 9000;

fn main() {
    println!("Max Speed: {}", MAX_SPEED);
}

16 - É possível alterar o valor de uma constante após sua declaração?

Playground!

Resposta
const MAX_SPEED: i32 = 100;

fn main() {    
    MAX_SPEED = 200; // erro: cannot assign to this expression
}

Não. Constantes são sempre imutáveis — a palavra-chave mut não pode ser usada com const de forma alguma. Qualquer tentativa de reatribuição resulta em erro de compilação.

17 - Quais são as principais diferenças entre constantes e variáveis imutáveis em Rust?

Playground!

Resposta
const CONSTANTE_GLOBAL: i32 = 100;

fn main() {
    let variavel_imutavel = 200;
    println!("Constante: {}, Variável: {}", CONSTANTE_GLOBAL, variavel_imutavel);

    // Constantes:
    // - Sempre imutáveis: 'mut' não é permitido de forma alguma (nem como tentativa);
    // - Tipo explícito obrigatório (ex: : i32);
    // - Avaliadas em tempo de compilação;
    // - Podem ser declaradas em escopo global (fora de funções).
    
    // Variáveis Imutáveis (let):
    // - Podem ser tornadas mutáveis com 'mut';
    // - O tipo pode ser inferido;
    // - Locais ao seu escopo;
    // - Podem ser definidas como o resultado de qualquer expressão.
}

18 - Como você usaria a macro format! para criar a string "O valor é: 42" a partir do número 42?

Playground!

Resposta
fn main() {
    let numero = 42;
    let numero_formatado = format!("O valor é: {}", numero);
    println!("{}", numero_formatado);
}

19 - Como você pode formatar o número "7" para que ele seja exibido como "0007" usando format!?

Playground!

Resposta
fn main() {
    let numero = 7;
    let numero_formatado = format!("{:04}", numero);
    println!("{}", numero_formatado);
}

20 - Como você formataria um número de ponto flutuante para mostrar exatamente 2 casas decimais?

Playground!

Resposta
fn main() {
    let pi = 3.14159265359;
    println!("Pi: {:.2}", pi);

    let pi_formatado = format!("{:.2}", pi);
    println!("Pi: {}", pi_formatado);    
}

21 - Demonstre como usar argumentos posicionais em format strings.

Playground!

Resposta
fn main() {
    let nome = "Snoopy";
    let idade = 8;
    let cidade = "Califórnia";
    
    // Argumentos posicionais
    println!("{0} tem {1} anos e mora na {2}", nome, idade, cidade);
    
    // Argumentos nomeados
    println!("{nome} tem {idade} anos e mora na {cidade}");
             
    // Misturado
    println!("{} tem {idade} anos e mora na {cidade}", nome);
}

22 - O que é shadowing em Rust? Explique com um exemplo de código e qual seria a saída.

Playground!

Resposta
fn main() {
    let x = 5;
    println!("Primeiro x: {}", x);

    let x = x + 1;
    println!("Segundo x: {}", x);

    let x = x * 2;
    println!("Terceiro x: {}", x);

    let x = "Olá";
    println!("Quarto x: {}", x);
}

23 - Qual será a saída do seguinte código?

Playground!

fn main () {
    let x = 5;
    let x = x + 1;
    {
        let x = x * 2;
        println!("O valor interno de x é: {}", x);
    }
    println!("O valor externo de x é: {}", x);
}
Resposta
fn main() {
    let x = 5;
    let x = x + 1; // x = 6
    {
        let x = x * 2; // x = 12 
        println!("O valor interno de x é: {}", x); // Saida: 12
    }
    println!("O valor externo de x é: {}", x); // Saida: 6
}

24 - Qual será a saída do seguinte código? Explique por quê.

Playground!

fn main () {    
    let a = 10;
    {
        let b = 20;
        println!("Dentro do bloco: a = {}, b = {}", a, b);
    }
    println!("Fora do bloco: b = {}", b);
}
Resposta
fn main() {
    let a = 10;
    {
        let b = 20;
        println!("Dentro do bloco: a = {}, b = {}", a, b);
        // Saida: Dentro do bloco: a = 10, b = 20
    }
    // println!("Fora do bloco: b = {}", b);
    // Erro: b não está no escopo
}

Tipos de Dados

Este capítulo explora os tipos de dados fundamentais disponíveis no Rust, cobrindo os blocos de construção essenciais que você usará para armazenar e manipular informações em seus programas. Compreender esses tipos de dados é crucial para escrever código Rust eficiente, pois cada tipo possui características específicas, requisitos de memória e casos de uso.

Uma das principais forças do Rust é o seu sistema de tipagem estática, o que significa que o compilador sabe o tipo exato de cada variável em tempo de compilação, proporcionando benefícios tanto em segurança quanto em desempenho. Assim como nos capítulos anteriores, exercícios práticos são fornecidos no final para reforçar sua compreensão e garantir que você esteja pronto para prosseguir com confiança.

u: inteiros não-assinados

São tipos de dados que só podem armazenar números inteiros positivos ou zero.

u8

#![allow(unused)]
fn main() {
// u8 = 0 a 255
let inteiro: u8 = 16;
println!("{}", inteiro);
}

u16

#![allow(unused)]
fn main() {
// u16 = 0 a 65_535
let inteiro: u16 = 32;
println!("{}", inteiro);
}

u32

#![allow(unused)]
fn main() {
// u32 = 0 a 4_294_967_295
let inteiro: u32 = 64;
println!("{}", inteiro);
}

u64

#![allow(unused)]
fn main() {
// u64 = 0 a 18_446_744_073_709_551_615
let inteiro: u64 = 128;
println!("{}", inteiro);
}

u128

#![allow(unused)]
fn main() {
// u128 = 0 a ...
let inteiro: u128 = 256;
println!("{}", inteiro);
}

i: inteiros assinados

São tipos de dados que só podem armazenar números inteiros positivos, negativos ou zero.

i8

#![allow(unused)]
fn main() {
// i8 = -128 a 127
let inteiro: i8 = -16;
println!("{}", inteiro);
}

i16

#![allow(unused)]
fn main() {
// i16 = -32_768 a 32_767
let inteiro: i16 = -32;
println!("{}", inteiro);
}

i32

#![allow(unused)]
fn main() {
// i32 = -2_147_483_648 a 2_147_483_647
let inteiro: i32 = -64;
println!("{}", inteiro);
}

i64

#![allow(unused)]
fn main() {
// i64 = -9_223_372_036_854_775_808 a 9_223_372_036_854_775_807
let inteiro: i64 = -128;
println!("{}", inteiro);
}

i128

#![allow(unused)]
fn main() {
// i128 =  ... a ...
let inteiro: i128 = -256;
println!("{}", inteiro);
}

f32 e f64: ponto flutuante

São tipos de dados que só podem armazenar números que possuem uma parte fracionária ou números reais, positivos, negativos ou zero.

f32

#![allow(unused)]
fn main() {
// f32 = -3.4e+38 a +3.4e+38
let flutuante: f32 =  64.;
println!("{}", flutuante);
}

f64

#![allow(unused)]
fn main() {
// f64 = -1.8e+308 to +1.8e+308
let flutuante: f64 =  128.;
println!("{}", flutuante);
}

bool: booleano

Representa apenas dois tipos de valores: true (verdadeiro) ou false (falso).

true

#![allow(unused)]
fn main() {
let booleano: bool = true;
println!("1 + 1 = 2? {}", booleano);
}

false

#![allow(unused)]
fn main() {
let booleano: bool = false;
println!("1 + 1 = 2? {}", booleano);
}

char: caractere

Usado para representar um único caractere e requer o uso de aspas simples (por exemplo, 'a').

#![allow(unused)]
fn main() {
let caractere: char = 'a';
println!("{}", caractere);
}
#![allow(unused)]
fn main() {
let simbolo: char = '⭐';
println!("{}", simbolo);
}

String e &str

Sequência de caracteres UTF-8 que pode formar uma palavra ou frase, incluindo letras, números, símbolos ou qualquer outro tipo de caractere especial.

String

#![allow(unused)]
fn main() {
let frase: String = String::from("Um pouco de Rust para hoje!");
println!("{}", frase);
}

&str

#![allow(unused)]
fn main() {
let frase: &str = "Chega de Rust por hoje!";
println!("{}", frase);
}

O tópico String e &str será abordado melhor em um capítulo posterior.

Tuplas

Combinam múltiplos valores de tipos diferentes em uma única estrutura de dados composta com um tamanho fixo.

inferência de tipos

#![allow(unused)]
fn main() {
let tipos_dados = ("a", 1);
println!("{:?}", tipos_dados);
}
#![allow(unused)]
fn main() {
let tipos_dados = ('b', 2.);
println!("{:?}", tipos_dados);
}

inferência com atribuição explícita

#![allow(unused)]
fn main() {
let tipos_dados: (&str, u8) = ("c", 3);
println!("{:?}", tipos_dados);
}
#![allow(unused)]
fn main() {
let tipos_dados: (String, bool) = (String::from("d"), true);
println!("{:?}", tipos_dados);
}

Desestruturação com tipos explícitos

#![allow(unused)]
fn main() {
let (texto, numero): (&str, i8);
(texto, numero) = ("e", 44);
println!("{}, {}", texto, numero);
}
#![allow(unused)]
fn main() {
let (texto, numero): (String, f64);
(texto, numero) = (String::from("f"), 128.5);
println!("{}, {}", texto, numero);
}

Desestruturação simples

#![allow(unused)]
fn main() {
let (letra, ativo): (char, bool) = ('e', false);
let saida =  (letra, ativo);
println!("{:?}", saida);
}
#![allow(unused)]
fn main() {
let pessoa = ("Gregorio", 64, 1.82);
let (nome, idade, altura) = pessoa;
println!("{}, {}, {}", nome, idade, altura);
}

Modificando Tuplas

Ao alterar valores de tupla, você precisa especificar o índice do elemento que deseja modificar. Os índices da tupla começam em 0 e correspondem à posição de cada elemento.

#![allow(unused)]
fn main() {
//                   0      1    2
let mut perfil = ("Alice", 25, 1.70);

println!("Nome: {:?}", perfil.0);
println!("Idade: {:?}", perfil.1);
println!("Altura: {:?}\n", perfil.2);

perfil.1 = 40;
perfil.2 = 1.55;

println!("Nome: {:?}", perfil.0);
println!("Idade: {:?}", perfil.1);
println!("Altura: {:?}", perfil.2);
}
#![allow(unused)]
fn main() {
let mut perfil = ("Julio", 90, 1.98);
println!("{:#?}", perfil);

perfil.0 = "Moana";
perfil.1 = 58;
perfil.2 = 1.62;

println!("{:#?}", perfil);
}

Array

Uma sequência de elementos de tamanho fixo onde todos os itens devem ser do mesmo tipo de dado.

#![allow(unused)]
fn main() {
let lista = ["Batata", "Cebola", "Alho", "Cenoura"];
println!("{:?}", lista);
}
#![allow(unused)]
fn main() {
let lista: [f32; 4] = [0.2, 0.4, 0.6, 0.8];
println!("{:?}", lista);
}
#![allow(unused)]
fn main() {
let lista: [&str; 4];
lista = ["Canadá", "Japão", "Brasil", "Egito"];
println!("{:?}", lista);
}
#![allow(unused)]
fn main() {
let [a, b, c]: [char; 3] = ['1', '2', '3'];
let lista = [a, b, c];
println!("{:?}", lista);
}
#![allow(unused)]
fn main() {
let lista: [String; 3] = [String::from("A1"), String::from("B2"), String::from("C3")];
let [a, b, c] = lista;
println!("{:?}, {:?}, {:?}", a, b, c);
}

Modificando Arrays

Ao alterar valores de array, você precisa especificar o índice do elemento que deseja modificar. Os índices do array começam em 0 e correspondem à posição de cada elemento:

#![allow(unused)]
fn main() {
//                0   1   2   3   4
let mut scores = [40, 50, 60, 70, 80];

println!("Score [0]: {}", scores[0]);
println!("Score [1]: {}", scores[1]);
println!("Score [2]: {}\n", scores[2]);

scores[0] = 10;
scores[1] = 20;
scores[2] = 30;

println!("Score [0]: {}", scores[0]);
println!("Score [1]: {}", scores[1]);
println!("Score [2]: {}", scores[2]);
}
#![allow(unused)]
fn main() {
let mut numero: [i32; 5] = [1, 2, 3, 4, 5];
println!("{:#?}", numero);

numero[0] = 10;
numero[2] = 30;
numero[4] = 50;

println!("{:#?}", numero);
}
#![allow(unused)]
fn main() {
let mut nomes: [&str; 3] = ["Cecília", "Maite", "Helena"];
println!("{:#?}", nomes);

nomes[0] = "Gael";
nomes[1] = "Theo";
nomes[2] = "Rafael";

println!("{:#?}", nomes);
}

Questões - Estruturas de Dados


01 - Declare uma variável com nome positivo do tipo u32 com o valor 100. Declare outra variável com nome negativo do tipo i32 com o valor -100. Imprima ambas. Agora, tente atribuir -5 à variável positivo. O que acontece ao tentar compilar e por quê?

Playground!

Resposta
fn main() {
    let positivo: u32 = 100;
    println!("{:?}", positivo);
   
    let negativo: i32 = -100;
    println!("{:?}", negativo);

    // Erro:
    // let positivo: u32 = -5;
}

02 - Escreva código Rust para declarar uma variável max_u8 do tipo u8 e atribua a ela o maior valor possível para esse tipo. Imprima esse valor e em seguida, no seu código, tente atribuir max_u8 + 1 a uma nova variável u8. O que acontece durante a execução?

Playground!

Resposta
fn main() {
    let max_u8: u8 = u8::MAX;
    println!("{:?}", max_u8);

    // erro: causaria um overflow (estouro)
    // let max_u8: u8 = u8::MAX + 1;
    // println!("{:?}", max_u8);
}

03 - Declare uma variável chamada populacao do tipo u64 e atribua a ela o valor "7_800_000_000". Em seguida, imprima o valor da variável formatada.

Playground!

Resposta
fn main() {
    let populacao: u64 = 7_800_000_000;
    println!("População: {populacao:?}");
}

04 - Você precisa armazenar a contagem de visualizações de vídeos, que pode chegar a bilhões, mas nunca será negativo. Escolha o tipo não assinado mais apropriado (u32 ou u64). Declare uma variável video_views com este tipo, atribua "2500000000" a ela e imprima.

Playground!

Resposta
fn main() {
    let video_views: u64 = 2_500_000_000;
    println!("{:?}", video_views);
}

05 - Declare duas variáveis, min_val_i8 e max_val_i8, ambas do tipo i8. Atribua a elas, respectivamente, o menor e o maior valor possível para o tipo i8. Imprima ambos os valores.

Playground!

Resposta
fn main() {
    let min_val_i8: i8 = i8::MIN;
    println!("{:?}", min_val_i8);
   
    let max_val_i8: i8 = i8::MAX;
    println!("{:?}", max_val_i8);
}

06 - Tente declarar uma variável valor_a do tipo u8 com 10 e valor_b do tipo u8 com -10. O que acontece com valor_b durante a compilação?

Playground!

Resposta
fn main() {
    let valor_a: u8 = 10;
    println!("{:?}", valor_a);

    let valor_b: u8 = -10;
    println!("{:?}", valor_b);
}

07 - Em um sistema embarcado com memória limitada, você precisa armazenar uma leitura de sensor que varia de -10.0 a +10.0 com duas casas decimais de precisão. Declare uma variável leitura_do_sensor usando f32 e atribua 7.89.

Playground!

Resposta
fn main() {
    let leitura_do_sensor: f32 = 7.89;
    println!("{:?}", leitura_do_sensor);
}

08 - Declare um caractere ASCII char_ascii = 'Z'; e um caractere unicode char_unicode = 'Ω';. Use std::mem::size_of_val(&char_ascii) e std::mem::size_of_val(&char_unicode) para imprimir o tamanho em bytes de cada um. O que você observa?

Playground!

Resposta
fn main() {
    let char_ascii: char = 'Z';
    println!("{:?}", char_ascii);

    let char_unicode: char = 'Ω';
    println!("{:?}", char_unicode);

    println!("{:?}", std::mem::size_of_val(&char_ascii));
    println!("{:?}", std::mem::size_of_val(&char_unicode));
}

09 - Tente declarar uma variável char com mais de um caractere, por exemplo: let letra: char = 'ab';. O que acontece ao tentar compilar?

Playground!

Resposta
fn main() {
    // erro: deve ter apenas um caractere
    let letra: char = 'ab';
    println!("{:?}", letra);
}

10 - Declare uma variável arquivo_carregado e atribua true. Declare apresenta_erro e atribua false. Imprima ambas e em seguida, tente atribuir o inteiro 1 a uma variável booleana. O que o compilador Rust diz?

Playground!

Resposta
fn main() {
    let arquivo_carregado: bool = true;
    println!("{:?}", arquivo_carregado);

    let apresenta_erro: bool = false;
    println!("{:?}", apresenta_erro);

    // Tipos incompatíveis, esperava-se `bool`, encontrado inteiro
    // let valor: bool = 1;
    // println!("{:?}", valor);
}

11 - Crie uma tupla registro que contenha um nome (&str), uma idade (u8), e uma nota de aprovação (f32). Exemplo: ("Maria", 22, 7.5). Imprima a tupla inteira.

Playground!

Resposta
fn main() {
    let registro: (&str, u8, f32) = ("Maria", 22, 7.5);
    println!("{:#?}", registro);
}

12 - Crie uma tupla chamada server_response que contenha um código de status HTTP (u16) e uma mensagem de resposta (&str), como (404, "Not Found"). Imprima a tupla.

Playground!

Resposta
fn main() {
    let server_response: (u16, &str) = (404, "Not Found");
    println!("{:?}", server_response);
}

13 - Dada a tupla let produto_info = ("Laptop XPTO", 1250.99, 15); (nome, preço, quantidade em estoque), acesse e imprima o preço e a quantidade usando a indexação de tupla (ex: product_info.1).

Playground!

Resposta
fn main() {    
    let produto_info: (&str, f32, u16) = ("Laptop XPTO", 1.250_000, 15);

    println!(
        "Produto: {} \nQuantidade em Estoque: {}",
        produto_info.0, produto_info.2
    );    
}

14 - Dada a tupla let color_rgb = (255, 128, 0);, desestruture-a nas variáveis red, green e blue. Imprima cada variável separadamente.

Playground!

Resposta
fn main() {
    let color_rgb: (u8, u8, u8) = (255, 128, 0);
    let (red, green, blue) = color_rgb;

    println!("Red: {} \nGreen: {} \nBlue: {}", red, green, blue);
}

15 - Declare uma tupla api_result com um booleano indicando sucesso, um u64 para um ID e uma string para uma mensagem. Ex: (true, 1234567890, String::from("Successful operation")). Imprima usando {:#?}.

Playground!

Resposta
fn main() {
    let api_result: (bool, u64, String) = (true, 1234567890, String::from("Successful operation"));
    println!("{:#?}", api_result);
}

16 - Declare uma tupla let config = ("localhost", 8080);. Tente modificar o segundo elemento para 8081 (ex: config.1 = 8081;). O que acontece ao compilar? Agora, redeclare-a como let mut config = ("localhost", 8080); e tente a mesma modificação.

Playground!

Resposta
fn main() {
    // erro: 
    // let config: (&str, u16) = ("localhost", 8080);
    // config.1 = 8081;
    
    let mut config: (&str, u16) = ("localhost", 8080);
    println!("{:?}", config);

    config.1 = 8081;
    println!("{:?}", config);
}

17 - Declare uma tupla mutável player_status para armazenar nome (&str), score (i32) e vidas (u8). Inicialize com ("Hero", 0, 3). Em seguida, modifique a pontuação para 1500 e as vidas para 2. Imprima a tupla atualizada.

Playground!

Resposta
fn main () {
    let mut player_status: (&str, i32, u8) = ("Hero", 0, 3);
    println!("Name: {}\nScore: {}\nVidas: {}\n", player_status.0, player_status.1, player_status.2);
    
    player_status.1 = 1500;
    player_status.2 = 2;
    println!("Name: {}\nScore: {}\nVidas: {}", player_status.0, player_status.1, player_status.2);
}

18 - Crie uma tupla mutável let mut point = (10.0, 20.0);. Modifique o primeiro elemento para 15.5 e o segundo para 25.0 usando a sintaxe de acesso por índice. Imprima a tupla.

Playground!

Resposta
fn main() {
    let mut point: (f32, f32) = (10., 20.);
    println!("{:#?}", point);

    point.0 = 15.5;
    point.1 = 25.;
    println!("{:#?}", point);
}

19 - Crie uma tupla mutável file_details contendo nome do arquivo (String), tamanho (u64) e se é editável (bool). Inicialize-a. Em seguida, modifique o nome do arquivo (anexando "_v2" ao nome original) e mude o status de editável. Imprima a tupla.

Playground!

Resposta
fn main () {
    let file_details: (String, u64, bool) = (String::from("test.txt"), 127, true);
    println!("{:#?}", file_details);

    let mut file_details_v2 = file_details;
    file_details_v2.0 = String::from("teste_v2.txt");
    file_details_v2.2 = false;

    println!("{:#?}", file_details_v2);
}

20 - Declare um array meses contendo os nomes dos três primeiros meses do ano como string slices. Imprima o nome do segundo mês (lembre-se da indexação baseada em zero).

Playground!

Resposta
fn main () {
    let meses: [&str; 3] = ["Janeiro", "Fevereiro", "Março"];

    println!("{:#?}\n", meses);
    println!("{:#?}", meses[1])
}

21 - Declare um array numeros de 6 elementos do tipo u32. Inicialize-o com os valores [1, 2, 4, 8, 16, 32]. Imprima o último elemento do array usando indexação.

Playground!

Resposta
fn main () {
    let numeros: [u32; 6] = [1, 2, 4, 8, 16, 32];
    println!("{numeros:#?}\n");
    
    let numeros: [u32; 6] = [1, 2, 4, 8, 16, 32];
    println!("{:#?}", numeros[5]);
}

22 - Declare um array let scores = [100, 90, 80];. Tente modificar o segundo elemento para 95. O que acontece? Agora, declare-o como mut, faça a modificação e imprima.

Playground!

Resposta
fn main () {
    let scores = [100, 90, 80];
    println!("{:?}", scores);

    // scores[1] = 95;
    // println!("{:?}", scores);

    let mut scores = [10, 30, 60];
    println!("{:?}", scores);

    scores[1] = 0;
    println!("{:?}", scores);
}

23 - Declare um array mutável contador de 4 elementos do tipo u16, inicializado com [10, 25, 5, 30]. Modifique a contagem do primeiro item para 12 e do terceiro para 8. Imprima o array atualizado.

Playground!

Resposta
fn main () {
    let mut contador: [u16; 4] = [10, 25, 5, 30];

    contador[0] = 12;
    contador[2] = 8;

    println!("{:?}", contador);
}

24 - Crie um array mutável servicos_ativos: [bool; 3] inicializado como [true, false, true]. Modifique o segundo serviço para true e o último para false. Imprima o array.

Playground!

Resposta
fn main () {
    let mut servicos_ativos:[bool; 3] = [true, false, true];
    println!("{:?}", servicos_ativos);

    servicos_ativos[1] = true;
    servicos_ativos[2] = false;
    println!("{:?}", servicos_ativos);
}

Operadores

Este capítulo se aprofunda nos diversos operadores disponíveis em Rust, que são ferramentas essenciais para realizar operações em dados e controlar o fluxo do programa. Os operadores permitem manipular valores, fazer comparações e executar operações lógicas que formam o núcleo de qualquer lógica de programação.

Dominar esses operadores é fundamental para escrever um código Rust expressivo e eficiente. Eles servem como os blocos de construção para operações e algoritmos mais complexos que você desenvolverá à medida que avança.

Operadores Aritméticos

Usados para cálculos matemáticos básicos.

+

#![allow(unused)]
fn main() {
let adi = 1 + 1;
println!("Adição = {:?}", adi);
}

-

#![allow(unused)]
fn main() {
let sub = 2 - 2;
println!("Subtração = {:?}", sub);
}

*

#![allow(unused)]
fn main() {
let mul = 3 * 3;
println!("Multiplicação = {:?}", mul);
}

/

#![allow(unused)]
fn main() {
let div = 4 / 4;
println!("Divisão = {:?}", div);
}

%

#![allow(unused)]
fn main() {
let rest = 5 % 5;
println!("Resto Divisão = {:?}", rest);
}

Operadores de Atribuição

Usados para atribuir valores a variáveis.

+=

#![allow(unused)]
fn main() {
let mut num: u8 = 10;

num += 1;
println!("10 += 1 = {}", num);
}

-=

#![allow(unused)]
fn main() {
let mut num: u8 = 10;

num -= 1;
println!("10 -= 1 = {}", num);
}

*=

#![allow(unused)]
fn main() {
let mut num: u8 = 10;

num *= 2;
println!("10 *= 2 = {}", num);
}

/=

#![allow(unused)]
fn main() {
let mut num: u8 = 20;

num /= 3;
println!("20 /= 3 = {}", num);
}

%=

#![allow(unused)]
fn main() {
let mut num: u8 = 6;

num %= 4;
println!("6 %= 4 = {}", num);
}

Precedência

A ordem na qual as operações são realizadas em uma expressão, sendo a ordem de prioridade: (), *, /, %, + e -

()

#![allow(unused)]
fn main() {
let preced: [i8; 2] = [5, 3];
println!("{:?}", preced[0] + preced[1] * preced[1]);

// ()
println!("{:?}", (preced[0] + preced[1]) * preced[1]);
}

*, / e %

#![allow(unused)]
fn main() {
let preced: [i8; 2] = [5, 3];
println!("{:?}", preced[0] * preced[1] / preced[1] % preced[1]);
}

+ e -

#![allow(unused)]
fn main() {
let preced: [i8; 2] = [5, 3];
println!("{:?}", preced[0] + preced[1] - preced[0] + preced[0] * preced[0]);
}

Comparação

O ato de verificar se dois ou mais itens são iguais, diferentes ou ordenados em relação um ao outro.

== (igual a)

#![allow(unused)]
fn main() {
let a = 1;
let b = 1;
println!("{}", a == b);
}
#![allow(unused)]
fn main() {
let a = 2;
let b = 3;
println!("{}", a == b);
}

!= (diferente de)

#![allow(unused)]
fn main() {
let a = 1;
let b = 1;
println!("{}", a != b);
}
#![allow(unused)]
fn main() {
let a = 2;
let b = 3;
println!("{}", a != b);
}

> (maior que)

#![allow(unused)]
fn main() {
let a = 1;
let b = 1;
println!("{}", a > b);
}
#![allow(unused)]
fn main() {
let a = 2;
let b = 3;
println!("{}", a > b);
}

< (menor que)

#![allow(unused)]
fn main() {
let a = 1;
let b = 1;
println!("{}", a < b);
}
#![allow(unused)]
fn main() {
let a = 2;
let b = 3;
println!("{}", a < b);
}

>= (maior ou igual)

#![allow(unused)]
fn main() {
let a = 1;
let b = 1;
println!("{}", a >= b);
}
#![allow(unused)]
fn main() {
let a = 2;
let b = 3;
println!("{}", a >= b);
}

<= (menor ou igual)

#![allow(unused)]
fn main() {
let a = 1;
let b = 1;
println!("{}", a <= b);
}
#![allow(unused)]
fn main() {
let a = 2;
let b = 3;
println!("{}", a <= b);
}

Lógicos

Relacionados a operações que combinam ou modificam valores booleanos (verdadeiro/falso) para produzir um único resultado booleano.

AND (E) - Somente verdadeiro quando ambos são verdadeiros

#![allow(unused)]
fn main() {
// AND = &&
println!("Verdadeiro && Verdadeiro = {}", true && true);
println!("Verdadeiro && Falso = {}", true && false);
println!("Falso && Verdadeiro = {}", false && true);
println!("Falso && Falso = {}", false && false);
}

OR (OU) - Verdadeiro quando pelo menos um é verdadeiro

#![allow(unused)]
fn main() {
// OR = ||
println!("Verdadeiro || Verdadeiro = {}", true || true);
println!("Verdadeiro || Falso = {}", true || false);
println!("Falso || Verdadeiro = {}", false || true);
println!("Falso || Falso = {}", false || false);
}

NOT (NÃO) - Sempre inverte o valor

#![allow(unused)]
fn main() {
// NOT = !
println!("!Verdadeiro = {}", !true);
println!("!Falso = {}", !false);
}

Você entenderá melhor seu uso quando estiver estudando estruturas de controle.

String e &str

A concatenação de String e &str é o processo de unir sequências de caracteres. Em Rust, você pode usar o operador + ou a macro format!() para concatenar strings.

string

#![allow(unused)]
fn main() {
let conc_texto_a: String = String::from("Sense");
let conc_texto_b: String = String::from(" Life");
println!("{}", conc_texto_a + &conc_texto_b);
}

&str

#![allow(unused)]
fn main() {
let conc_texto_a: &str = "Calvin";
let conc_texto_b: &str = " e Haroldo";
println!("{}", conc_texto_a.to_owned() + conc_texto_b);
}

string + &str

#![allow(unused)]
fn main() {
let parte_a: &str = "ão";
let parte_b: String = String::from("Lampi");
println!("{}", parte_b + parte_a);
}
#![allow(unused)]
fn main() {
let parte_a: &str = "O Menino";
let parte_b: String = String::from("Maluquinho");
println!("{}", parte_a.to_owned() + " " + &parte_b);
}
#![allow(unused)]
fn main() {
let parte_a: String = String::from("Rei de");
let parte_b: &str = "Lata";

let resultado: String =  parte_a + " " + parte_b;
println!("{}", resultado);
}

Tuplas

Armazenam múltiplos itens de dados de tipos diferentes em uma estrutura de tamanho fixo.

tupla

#![allow(unused)]
fn main() {
let tup: (u8, u8) = (1, 4);
println!("{:?}", tup.0 + tup.1);
}
#![allow(unused)]
fn main() {
let tup: (u8, u8);
tup = (3, 8);
println!("{:?}", tup.0 + tup.1);
}

tupla + tupla

#![allow(unused)]
fn main() {
let tup: ((u8, u8),(u8, u8)) = ((2, 4),(6, 16));

println!("{:?}", tup.0.0 + tup.0.1);
println!("{:?}", tup.1.0 + tup.1.1);
println!("{:?}", tup.0.0 + tup.1.0);
println!("{:?}", tup.0.1 + tup.1.1);
}
#![allow(unused)]
fn main() {
let tup_01: (u8, u8) = (1, 4);
let tup_02: (u8, u8) = (14, 9);

let result = tup_01.0 + tup_01.1 + tup_02.0 + tup_02.1;
println!("{:?}", result);
}

Array

Uma lista de itens de dados que são todos do mesmo tipo e têm um tamanho fixo.

array

#![allow(unused)]
fn main() {
let arr: [u8; 2] = [1, 4];
println!("{:?}", arr[0] + arr[1]);
}
#![allow(unused)]
fn main() {
let arr: [u8; 2];
arr = [3, 8];
println!("{:?}", arr[0] + arr[1]);
}

array + array

#![allow(unused)]
fn main() {
let arr: [[u8; 2]; 2] = [[2, 4], [6, 16]];

println!("{:?}", arr[0][0] + arr[0][1]);
println!("{:?}", arr[1][0] + arr[1][1]);
println!("{:?}", arr[0][0] + arr[1][0]);
println!("{:?}", arr[0][1] + arr[1][1]);
}
#![allow(unused)]
fn main() {
let arr_01: [u8; 2] = [1, 4];
let arr_02: [u8; 2] = [14, 9];

let result = arr_01[0] + arr_01[1] + arr_02[0] + arr_02[1];
println!("{:?}", result);
}

Questões - Operadores


01 - Escreva um programa que declare duas variáveis inteiras, a com o valor 15 e b com o valor 7, e imprima a soma delas.

Playground!

Resposta
fn main() {
    let a: u8 = 15;
    let b: u8 = 7;

    println!("{:?}", a + b);
}

02 - Crie um código que subtraia o valor 3 de uma variável chamada total que é inicialmente igual a 10, e exiba o resultado.

Playground!

Resposta
fn main() {
    let total = 10;
    let sub = total - 3;
    println!("{:?}", sub);

    let mut total = 10;
    total -= 3;
    println!("{:?}", total);
}

03 - Desenvolva um programa que multiplique duas variáveis, x igual a 6 e y igual a 8, e mostre o produto.

Playground!

Resposta
fn main() {
    let x: u8 = 6;
    let y: u8 = 8;

    let result: u8 = x * y;
    println!("{:?}", result);
}

04 - Implemente um código que divida o número 20 por 5 e imprima o quociente.

Playground!

Resposta
fn main() {
    let result = 20 / 5;
    println!("{}", result);
}

05 - Escreva um programa que calcule o resto da divisão de 23 por 4 e imprima o resultado.

Playground!

Resposta
fn main() {
    let mut resto: u8 = 23;
    resto %= 4;

    println!("{:?}", resto);
}

06 - Declare duas variáveis num1 = 12 e num2 = 5 e imprima o resultado da soma delas diretamente dentro da macro println!.

Playground!

Resposta
fn main() {
    let num1: u8 = 12;
    let num2: u8 = 5;

    println!("{:?}", num1 + num2);
}

07 - Crie uma variável imutável chamada valor que seja a soma de 9 e 2, e imprima seu valor.

Playground!

Resposta
fn main() {
    let valor: u8 = 9 + 2;
    println!("{:?}", valor);
}

08 - Declare uma variável mutável chamada contador com um valor inicial de 5. Incremente-a em 3 usando o operador de atribuição de adição (+=) e imprima o novo valor.

Playground!

Resposta
fn main() {
    let mut contador: u8 = 5;
    contador += 3;

    println!("{:?}", contador);
}

09 - Crie uma variável mutável score inicializada com 20. Decremente-a em 5 usando o operador de atribuição de subtração (-=) e exiba o valor final.

Playground!

Resposta
fn main() {
    let mut score: u8 = 20;
    score -= 5;

    println!("{:?}", score);
}

10 - Declare uma variável mutável numero com o valor 2. Multiplique-a por 4 usando o operador de atribuição de multiplicação (*=) e imprima o resultado.

Playground!

Resposta
fn main() {
    let mut numero: u8 = 2;
    numero *= 4;

    println!("{:?}", numero);
}

11 - Inicialize uma variável mutável size com 30. Divida-a por 6 usando o operador de atribuição de divisão (/=) e mostre o valor resultante.

Playground!

Resposta
fn main() {
    let mut size: u8 = 30;
    size /= 6;

    println!("{:?}", size);
}

12 - Declare uma variável mutável numero com o valor 17. Calcule o resto da divisão por 5 usando o operador de atribuição de resto (%=) e imprima o valor.

Playground!

Resposta
fn main() {
    let mut numero: u8 = 17;
    numero %= 5;

    println!("{:?}", numero);
}

13 - Declare duas variáveis do tipo &str, part1 com Hello, e part2 com Rust!. Concatene-as e imprima o resultado.

Playground!

Resposta
fn main() {
    let part1: &str = "Hello, ";
    let part2: &str = "Rust!";

    println!("{}{}", part1, part2);
}

14 - Crie duas variáveis do tipo string, s1 = "Linguagem " e s2 = "Rust.". Concatene-as e imprima a string resultante.

Playground!

Resposta
fn main() {
    let s1: String = String::from("Linguagem ");
    let s2: String = String::from("Rust.");

    println!("{:?}", s1 + &s2);
}

15 - Declare uma variável do tipo &str chamada numero com o valor "Numero: ". Crie uma variável do tipo string chamada numero_str com o valor "42". Concatene-as e imprima o resultado.

Playground!

Resposta
fn main() {
    let numero: &str = "Numero: ";
    let numero_str: String = String::from("42");

    println!("{:?}", numero.to_owned() + &numero_str);
}

16 - Declare uma tupla com dois i32. Inicialize-a com os valores (5, -2). Imprima a multiplicação desses dois valores.

Playground!

Resposta
fn main() {
    let tup: (i32, i32) = (5, -2);
    println!("{:?}", tup.0 * tup.1);
}

17 - Crie uma tupla aninhada: ((1, 2), (3, 4)). Some o primeiro elemento da primeira tupla ao segundo elemento da segunda tupla e imprima o resultado.

Playground!

Resposta
fn main() {
    let tup: ((u8, u8), (u8, u8)) = ((1, 2), (3, 4));
    println!("{:?}", tup.0 .0 + tup.1 .1);
}

18 - Declare duas tuplas, t1 com (2, 5) e t2 com (8, 1). Some todos os elementos das duas tuplas e imprima o total.

Playground!

Resposta
fn main() {
    let t1: (u8, u8) = (2, 5);
    let t2: (u8, u8) = (8, 1);

    println!("{:?}", t1.0 + t1.1 + t2.0 + t2.1);
}

19 - Declare um array = [i32; 5] com os valores [1, 3, 5, 7, 9]. Imprima a soma do primeiro e último elementos.

Playground!

Resposta
fn main() {
    let arr: [i32; 5] = [1, 3, 5, 7, 9];
    println!("{:?} + {:?} = {:?}", arr[0], arr[4], arr[0] + arr[4]);
}

20 - Crie um array de [u16; 3]. Inicialize-o com os valores [10, 20, 30]. Imprima o produto de todos os elementos.

Playground!

Resposta
fn main() {
    let arr: [u16; 3];
    arr = [10, 20, 30];

    println!("{:?}", arr[0] * arr[1] * arr[2]);
}

21 - Declare um array multidimensional 2x2 com inteiros. Multiplique todos os elementos e imprima o resultado.

Playground!

Resposta
fn main() {
    let arr: [[i8; 2]; 2];
    arr = [[2, 2], [4, 4]];

    println!("{:?}", arr[0][0] * arr[0][1] * arr[1][0] * arr[1][1]);
}

22 - Declare uma variável x com valor 1. Crie um bloco interno onde você declare uma variável y com valor 2. Dentro do bloco, imprima a soma de x e y. Fora do bloco, tente imprimir y (o que acontecerá?).

Playground!

Resposta
fn main() {
    let x: u8 = 1;
    {
        let y: u8 = 2;
        println!("{:?}", x + y);
    }
    
    println!("{:?}", x);
    // println!("{:?}", y); // Erro: `y` fora do escopo
}

23 - Declare uma variável level1 com valor 10. Abra um novo bloco e declare uma variável level2 com valor 20. Dentro deste bloco, crie outro bloco e declare level3 com valor 30. Imprima a soma de level1, level2 e level3 dentro do bloco mais interno.

Playground!

Resposta
fn main() {
    let level1: u8 = 10;
    {
        let level2: u8 = 20;
        {
            let level3: u8 = 30;
            println!("{:?}", level1 + level2 + level3);
        }
        println!("{:?}", level2);
    }
    println!("{:?}", level1);
}

24 - Declare uma variável principal com valor 100. Crie um bloco onde você declare uma variável com o mesmo nome e atribua o valor 50.0. Imprima o valor da variável dentro do bloco e fora do bloco.

Playground!

Resposta
fn main() {
    let principal: u8 = 100;
    println!("{:?}", principal);
    {
      let principal: f32 = 50.;
      println!("{:?}", principal);
    }
    println!("{:?}", principal);
}

25 - Usando os valores de um array var = [2, 3], escreva um código que calcule e imprima o resultado de (var[0] + var[1]) * var[1].

Playground!

Resposta
fn main() {
    let var: [u8; 2] = [2, 3];
    println!("{:?}", (var[0] + var[1]) * var[1]);
}

26 - Ainda com a variável var = [2, 3], calcule e imprima var[0] * var[1] / var[1] % var[1].

Playground!

Resposta
fn main() {
    let var: [u8; 2] = [2, 3];
    println!("{:?}", var[0] * var[1] / var[1] % var[1]);
}

27 - Calcule e imprima var[0] + var[1] − var[0] + var[0] * var[0]. (Usando var com [2, 3]).

Playground!

Resposta
fn main() {
    let var: [u8; 2] = [2, 3];
    println!("{:?}", var[0] + var[1] - var[0] + var[0] * var[0]);
}

28 - Calcule e imprima ((var[0] + var[1]) − (var[0] + var[0]) * var[0]). (Usando var com [2, 3]).

Playground!

Resposta
fn main() {
    let var: [i8; 2] = [2, 3];
    println!("{:?}", (var[0] + var[1]) - (var[0] + var[0]) * var[0]);
}

29 - Declare duas variáveis inteiras, num1 com valor 10 e num2 com valor 10. Escreva um código que imprima se num1 é igual a num2 (==).

Playground!

Resposta
fn main() {
    let num1: i8 = 10;
    let num2: i8 = 10;

    println!("Num1 = Num2? {:?} ", num1 == num2);
}

30 - Declare duas variáveis de ponto flutuante, f1 com 3.14 e f2 com 2.71. Escreva um código que imprima se f1 é diferente de f2 (!=).

Playground!

Resposta
fn main() {
    let f1: f32 = 3.14;
    let f2: f32 = 2.71;

    println!("f1 != f2? {}", f1 != f2);
}

31 - Declare duas variáveis inteiras, idade_a com 25 e idade_b com 30. Escreva um código que imprima se idade_a é maior que idade_b (>).

Playground!

Resposta
fn main() {
    let idade_a: u8 = 25;
    let idade_b: u8 = 30;

    println!("Idade A > Idade B? {}", idade_a > idade_b);
}

32 - Declare duas variáveis inteiras, point1 com 5 e point2 com 8. Escreva um código que imprima se point1 é menor que point2 (<).

Playground!

Resposta
fn main() {
    let point1: u8 = 5;
    let point2: u8 = 8;

    println!("Point1 < Point2? {}", point1 < point2);
}

33 - Declare duas variáveis inteiras, nota_a com 7 e nota_b com 7. Escreva um código que imprima se nota_a é maior ou igual a nota_b (>=).

Playground!

Resposta
fn main() {
    let nota_a: u8 = 7;
    let nota_b: u8 = 7;

    println!("Nota A >= Nota B? {}", nota_a >= nota_b);
}

34 - Declare duas variáveis float, altura_a com 1.70 e altura_b com 1.65. Escreva um código que imprima se altura_a é menor ou igual a altura_b (<=).

Playground!

Resposta
fn main() {
    let altura_a: f32 = 1.70;
    let altura_b: f32 = 1.65;

    println!("Altura A <= Altura B? {}", altura_a <= altura_b);
}

35 - Declare uma variável temp_a com 22.5 e temp_b com 20.0. Verifique se temp_a é maior que temp_b (>) e imprima.

Playground!

Resposta
fn main() {
    let temp_a: f32 = 22.5;
    let temp_b: f32 = 20.;

    println!("Temperatura A > Temperatura B? {}", temp_a > temp_b);
}

36 - Declare uma variável count_a com 100 e count_b com 99. Verifique se count_a é menor que count_b (<) e imprima.

Playground!

Resposta
fn main() {
    let count_a: u8 = 100;
    let count_b: u8 = 99;

    println!("Count A < Count B? {}", count_a < count_b);
}

37 - Declare duas variáveis u8, val_a com 8 e val_b com 3. Calcule a soma, subtraia 1 do resultado, e imprima.

Playground!

Resposta
fn main() {
    let val_a: u8 = 8;
    let val_b: u8 = 3;

    println!("{:?}", (val_a + val_b) - 1);
}

38 - Declare um array [i32; 3] = [2, 4, 6]. Divida cada elemento por 2 (usando atribuição de divisão se aplicável) e imprima o array resultante.

Playground!

Resposta
fn main() {
    let mut arr: [i32; 3] = [2, 4, 6];

    arr[0] /= 2;
    arr[1] /= 2;
    arr[2] /= 2;

    println!("{:#?}", arr);
}

39 - Declare uma tupla (f64, f64) = (2.5, 3.5). Some os elementos e imprima o resultado formatado com duas casas decimais.

Playground!

Resposta
fn main() {
    let tup: (f64, f64) = (2.5, 3.5);
    let result: f64 = tup.0 + tup.1;

    println!("{:.2}", result);
}

40 - Declare uma variável mensagem do tipo &str com "Start". Anexe a ela a String " -> End". Imprima o valor final de mensagem.

Playground!

Resposta
fn main() {
    //&str
    let mensagem: &str = "Start";
    println!("{}", mensagem.to_owned() + " -> End");
}
fn main() {
    // string
    let mut mensagem: String = String::from("Start");
    mensagem += " -> End";
    println!("{}", mensagem);
}

String e &str

Este capítulo aborda os tipos de string no Rust para manipulação de texto. Você aprenderá sobre literais de string (&str) e slices imutáveis, além de strings de propriedade (String) para criação dinâmica, incluindo métodos como push e push_str.

Cada seção inclui perguntas de prática para reforçar sua compreensão desses construtos essenciais de manipulação de texto.

Strings

Strings são sequências de caracteres UTF-8 que podem formar uma palavra ou frase, incluindo letras, números, símbolos ou qualquer outro tipo de caractere especial.

new()

#![allow(unused)]
fn main() {
// cria uma string vazia
let cria_string: String = String::new();
println!("{}", cria_string);
}

from()

#![allow(unused)]
fn main() {
// cria uma string a partir de um literal de string (&str)
let cria_string: String = String::from("Grande texto!");
println!("{}", cria_string);
}

to_string()

#![allow(unused)]
fn main() {
// converte um literal de string (&str) em uma string
let cria_string: String = "Mais um grande texto!".to_string();
println!("{}", cria_string);
}

mut

#![allow(unused)]
fn main() {
let mut cria_string: String = String::from("Quase um grande texto!");
println!("{}", cria_string);

cria_string = "Último grande texto!".to_string();
println!("{}", cria_string);
}

&str

Também conhecido como string slice ou fatia de string, representa uma referência imutável a uma sequência de texto UTF-8. É usado como string sem a necessidade de alocar memória no heap.

&str

#![allow(unused)]
fn main() {
let cria_str: &str = "Pequeno texto!";
println!("{}", cria_str);
}
#![allow(unused)]
fn main() {
let cria_str = "Outro pequeno texto!";
println!("{}", cria_str);
}

Métodos - Parte 1

Usados para manipular e modificar o conteúdo de texto.

push()

#![allow(unused)]
fn main() {
// adiciona um caractere
let mut text = String::from("Hello");
text.push(',');
text.push(' ');
text.push('w');
text.push('o');
text.push('r');
text.push('l');
text.push('d');
text.push('!');
println!("{:?}", text);
}

push_str()

#![allow(unused)]
fn main() {
// adiciona uma fatia de string
let mut text = String::from("Hello");
text.push_str(", world!");
println!("{:?}", text);
}

slice()

#![allow(unused)]
fn main() {
// retorna só uma parte da string
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// H e l l o ,   w o r l  d  !
let cria_str = "Hello, world!!";
let slice_str = &cria_str[0..3];
println!("{}", slice_str);
}

pop()

#![allow(unused)]
fn main() {
// remove o último caractere
let mut text = String::from("Hello, world!");
let _text_last = text.pop();
let _text_last = text.pop();
let text_last = text.pop();
println!("{:?}", text_last);
println!("{:?}", text);
}

insert()

#![allow(unused)]
fn main() {
// insere caracteres em uma posição especifica
// 0 1 2 3 4 5 6
// H e l l o ,  
let mut text = String::from("Hello,");
text.insert(6,  ' ');
text.insert(7,  'w');
text.insert(8,  'o');
text.insert(9,  'r');
text.insert(10, 'l');
text.insert(11, 'd');
text.insert(12, '!');
println!("{:?}", text);
}

remove()

#![allow(unused)]
fn main() {
// remove caracteres em uma posição especifica
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// H e l l o ,   w o r l  d  !
let mut text: String = String::from("Hello, world!");
let _text_letter = text.remove(11);
let _text_letter = text.remove(10);
let _text_letter = text.remove(9);
println!("{}", text);
}

len()

#![allow(unused)]
fn main() {
// retorna o comprimento da string em bytes
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// H e l l o ,   w o r l  d  !
let text: String = String::from("Hello, world!");
let number = text.len();
println!("{}", number);
}

clear()

#![allow(unused)]
fn main() {
// remove todo o conteúdo
let mut text: String = String::from("Hello, world!");
text.clear();
println!("{}", text);
}

truncate()

#![allow(unused)]
fn main() {
// corta a string em um índice específico
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// H e l l o ,   w o r l  d  !
let mut text: String = String::from("Hello, world");
text.truncate(5);
println!("{}", text);
}

Métodos - Parte 2

Usados para manipulação e modificação de conteúdo de texto.

is_empty()

#![allow(unused)]
fn main() {
// verifica se a string está vazia
let text = "Hello, world!";
println!("{}", text.is_empty());
}

contains()

#![allow(unused)]
fn main() {
// verifica se contém substring
let text = "Hello, world!";
println!("{}", text.contains("ello"));
}

starts_with() / ends_with()

#![allow(unused)]
fn main() {
// verifica se a string começa/termina com a substring fornecida
let text = "Hello, world!";
println!("{}", text.starts_with("He"));
println!("{}", text.ends_with("d!"));
}

find()

#![allow(unused)]
fn main() {
// encontra posição(índice) de substring
let text = "Hello, world!";
println!("{:?}", text.find("H"));
}

to_uppercase() / to_lowercase()

#![allow(unused)]
fn main() {
// conversão para maiúsculas/minúsculas
let text = "Hello, world!";
println!("{:?}", text.to_uppercase());
println!("{:?}", text.to_lowercase());
}

trim()

#![allow(unused)]
fn main() {
// remove espaços das extremidades
let text = "  Hello, world!  ";
println!("{:?}", text.trim());
}

replace()

#![allow(unused)]
fn main() {
// substitui todas as ocorrências
let text = "Hello, world!";
println!("{:?}", text.replace("word", "Snoopy"));
}

replacen()

#![allow(unused)]
fn main() {
// substitui apenas N ocorrências
let text = "Hello, world!";
println!("{:?}", text.replacen("o", "a", 1));
}

Entrada de Dados

Refere-se à entrada de dados, ou seja, à sua captura, validação e processamento.

std::io

// importa o módulo io
use std::io;

fn main () {
    println!("Entrada de texto:");
    let mut input:String = String::new();
    io::stdin().read_line(&mut input).expect("Erro de entrada de dados!");
    // io::stdin().read_line(&mut input).unwrap();
}
  • unwrap() - Se ocorrer um erro, o programa trava com um panic;
  • expect() - Se ocorrer um erro, ele trava, mas com a sua mensagem personalizada.

char

use std::io;

fn main() {
    println!("Entrada do caractere:");
    let mut input = String::new();
    io::stdin()
        .read_line(&mut input)
        .expect("Erro de entrada de dados!");

    // trim() remove espaços em branco, chars() itera sobre caracteres, next() pega o primeiro
    let ch: char = input.trim().chars().next().unwrap();
    println!("{}", ch);
}

match

use std::io;

fn main() {
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();

    match input.trim().parse::<u8>() {
        Ok(input) => input,
        Err(_) => {
            println!("Erro!");
            return;
        }
    };
}
use std::io;

fn main () {
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("Erro de entrada de dados!");

    let ch: u8 = match input.trim().parse() {
        Ok(n) => n,
        Err(_) => {
          println!("Erro de entrada!");
          return;
        }
    };  
}

Questões - String and &str


01 - Escreva um código que crie uma string vazia e a imprima.

Playground!

Resposta
fn main() {
    let cria_string: String = String::new();
    println!("{}", cria_string);
}

02 - Crie uma string a partir do literal de string "Pequeno, texto!".

Playground!

Resposta
fn main() {
    let literal_string: String = String::from("Pequeno, texto!");
    println!("{}", literal_string);
}

03 - Declare uma variável que contenha &str com o valor "Aprendendo Rust".

Playground!

Resposta
fn main() {
    let texto: &str = "Aprendendo Rust";
    println!("{}", texto);
}

04 - Dada uma string, escreva o código para obter um &str que represente toda a string.

Playground!

Resposta
fn main() {
    let entrada_string: String = String::from("Aprendendo Rust!");
    let entrada_str: &str = &entrada_string;
    println!("{}", entrada_str);
}
fn main() {
    let entrada_string: String = String::from("Aprendendo Rust!");
    let entrada_str: &str = entrada_string.as_str();
    println!("{}", entrada_str);
}

05 - Escreva um código que receba um texto em string e o converta para &str e, em seguida, o imprima na tela.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com texto:");
    let mut entrada_string: String = String::new();
    io::stdin()
        .read_line(&mut entrada_string)
        .expect("Erro de entrada de dados!");
    let texto_string: &str = entrada_string.as_str();
    println!("\nTexto convertido para &str: {}", texto_string.trim());
}

06 - Converta um string = 123 em um inteiro.

Playground!

Resposta
fn main() {    
    let text: &str = "123";
    let num: u8 = text.parse().expect("Erro ao converter dados!");
    println!("{}", num);    
}
fn main() {
    let text: &str = "123";
     
    let num = match text.parse::<u8>() {
        Ok(num) => num,
        Err(_) => {
            println!("Erro ao converter dados!");
            return;
        }
    };
    println!("{}", num);
}

07 - Use o método .to_string() ou String::from() para criar uma nova string concatenando um &str e uma string existente.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com texto:");
    let mut entrada_texto: String = String::new();
    io::stdin()
        .read_line(&mut entrada_texto)
        .expect("Erro de entrada de dados!");

    let texto_a: &str = &entrada_texto.as_str().trim();
    let texto_b: String = String::from(" + string!");

    println!("{}", texto_a.to_string() + &texto_b);
}

08 - Crie uma string mutável e anexe um &str a ela usando o método push_str().

Playground!

Resposta
fn main() {
    let mut string_mutavel: String = String::from("Pequeno, ");
    string_mutavel.push_str("texto!");
    println!("{}", string_mutavel);
}

09 - Adicione um único caractere (char) ao final de uma string mutável.

Playground!

Resposta
fn main() {    
    let mut unico_char: String = String::from("Pequeno, texto");
    let caractere: char = '!';

    unico_char.push(caractere);
    println!("{}", unico_char);
}

10 - Combine um &str, uma string e um número em uma nova string usando a macro format!.

Playground!

Resposta
fn main() {
    let var_str: &str = "1";
    let var_string: String = String::from("2");
    let var_u8: u8 = 3;

    // a macro format! cria uma nova string
    let result = format!("{}{}{}", var_str, var_string, var_u8);
    println!("{}", result);
}

11 - Crie uma nova string removendo todos os espaços em branco de uma string.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com texto:");
    let mut entrada_texto: String = String::new();
    io::stdin().read_line(&mut entrada_texto).err();

    let remove_espaco = entrada_texto.replace(" ", "");
    println!("\nSem espaços = {}", remove_espaco.trim());
}

12 - Substitua todas as ocorrências da substring erro por sucesso em um &str, criando uma nova string.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com texto:");
    let mut entrada_texto: String = String::new();
    io::stdin().read_line(&mut entrada_texto).err();

    let novo_texto = entrada_texto.replace("erro", "sucesso");
    println!("{}", novo_texto);
}

13 - Substitua apenas a primeira ocorrência de antes por depois em um &str, criando uma nova string.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com uma frase:");
    let mut entrada_frase: String = String::new();
    io::stdin().read_line(&mut entrada_frase).err();

    let frase = entrada_frase.replacen("antes", "depois", 1);
    println!("{}", frase);
}

14 - Verifique se um &str contém a substring Rust.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com uma frase:");
    let mut entrada_texto: String = String::new();
    io::stdin().read_line(&mut entrada_texto).err();

    if entrada_texto.contains("Rust") {
        println!("\n{} - contém 'Rust'", entrada_texto.trim());
    } else {
        println!("\n{} - não contém 'Rust'", entrada_texto.trim());
    }
}

15 - Verifique se um nome de arquivo em uma string termina com o sufixo .rs

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com o nome do arquivo:");
    let mut entrada_texto: String = String::new();
    io::stdin().read_line(&mut entrada_texto).err();

    if entrada_texto.trim().ends_with(".rs") {
        println!("\n{} - termina com '.rs'", entrada_texto.trim());
    } else {
        println!("\n{} - não termina com '.rs'", entrada_texto.trim());
    }
}

16 - Verifique se um &str começa com o prefixo https://.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com link:");
    let mut entrada_link: String = String::new();
    io::stdin().read_line(&mut entrada_link).err();

    if entrada_link.starts_with("https://") {
        println!("\n{} - começa com 'https://'", entrada_link.trim());
    } else {
        println!("\n{} - não começa com 'https://'", entrada_link.trim());
    }
}

17 - Crie um código que receba uma string e retorne uma fatia contendo apenas a primeira palavra. Assuma que as palavras são separadas por espaços.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com uma frase:");
    let mut entrada_frase: String = String::new();
    io::stdin().read_line(&mut entrada_frase).err();

    let frase = entrada_frase.split_whitespace().next();
    println!("{}", frase.unwrap());
}

18 - Encontre o índice de byte inicial da primeira ocorrência da substring rust.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com a frase:");
    let mut entrada_frase: String = String::new();
    io::stdin().read_line(&mut entrada_frase).err();

    if let Some(indice) = entrada_frase.find("rust") {
        println!("\nÍndice de bytes: {}", indice);
    } else {
        println!("\nNão tem: rust");
    }
}

19 - Escreva uma função que aceite uma string e retorne seu primeiro caractere como um char.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com a palavra:");
    let mut entrada_palavra: String = String::new();
    io::stdin().read_line(&mut entrada_palavra).err();

    let primeira_letra: char = entrada_palavra.trim_start().chars().next().unwrap_or(' ');
    println!("Primeira letra = {}", primeira_letra);
}

20 - Escreva um código que conte o número de caracteres (char) em um &str, não o número de bytes.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com uma palavra:");
    let mut entrada_palavra: String = String::new();
    io::stdin().read_line(&mut entrada_palavra).err();

    let palavra = entrada_palavra.trim().replace(" ", "");
    println!("{}", palavra);
    println!("{:?}", palavra.chars().count());
}

21 - Escreva um código que receba um &mut string e substitua todos os caracteres a minúsculos por A maiúsculos, modificando a string original.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com uma frase:");
    let mut entrada_frase: String = String::new();
    io::stdin().read_line(&mut entrada_frase).err();

    let frase = entrada_frase.trim().replace("a", "A");
    println!("{}", frase);    
}

22 - Escreva um código que remova o último caractere de uma string.

Playground!

Resposta
use std::io;

fn main() {
    println!("Entre com texto:");
    let mut entrada_palavra: String = String::new();
    io::stdin()
        .read_line(&mut entrada_palavra)
        .expect("Erro de entrada de dados!");

    let mut palavra: String = entrada_palavra.trim_end().to_string();
    palavra.pop();
    println!("{}", palavra);
}

23 - Use o método .clear() para limpar uma string sem desalocar sua capacidade de memória.

Playground!

Resposta
fn main() {
    let mut var_string: String = String::with_capacity(50);
    var_string.push_str("Pequeno, grande texto!");

    println!("String = {}", var_string);
    println!("Capacidade = {}", var_string.capacity());
    println!("Tamanho = {}", var_string.len());
    println!("");

    var_string.clear();
    println!("String = {}", var_string);
    println!("Capacidade = {}", var_string.capacity());
    println!("Tamanho = {}", var_string.len());
}