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;
- Experimentar sem a necessidade de instalar nada.
Acesse: https://play.rust-lang.org
Instalando
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
Desinstalando
Se em algum momento você quiser desinstalar o Rust:
rustup self uninstall
Editores e IDEs
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
[[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/
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 muito simples 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. }
//!
#![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. /* ... */ */ }
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!"); }
Nota: Quando estiver desenvolvendo um programa, pode redirecionar a saída normal para um arquivo usando (>) e as mensagens de erro para o terminal usando (eprint).
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() { // permite todas as barra invertidas 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
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); }
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 = 87; println!("Qual sua idade? {}", idade); idade = 49; println!("Qual sua idade? {}", idade); }
Constante
A constante é uma identificador com valor fixo e imutável, tipo explícito e pode ser declarada em qualquer escopo.
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 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?
Resposta
fn main() { // Este é um comentário de linha única }
02 - Qual é a sintaxe para comentários de bloco em Rust?
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.
Resposta
fn main() { /* Inicio do comentário externo // Este é um comentário 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?
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?
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!.
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!?
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.
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?
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.
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?
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.
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.
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?
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?
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?
Resposta
const MAX_SPEED: i32 = 100; fn main() { MAX_SPEED = 200; }
17 - Quais são as principais diferenças entre constantes e variáveis imutáveis em Rust?
Resposta
const CONSTANTE_GLOBAL: i32 = 100; fn main() { let variavel_imutavel = 200; println!("Constante: {}, Variável: {}", CONSTANTE_GLOBAL, variavel_imutavel); // Constantes: // - Sempre imutáveis (a palavra-chave 'mut' não é permitida); // - Tipo explícito (ex: : i32); // - 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?
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!?
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?
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.
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.
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?
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ê.
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; let inteiro: i64 = 9_223_372_036_854_775_807; 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, falso): (char, bool) = ('e', false); let saida = (letra, falso); 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ê?
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?
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!("{:?}"); }
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.
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.
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.
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?
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.
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?
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?
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?
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.
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.
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).
Resposta
fn main() { let produto_info: (&str, f32, u16) = ("Laptop XPTO", 1.250_000, 15); let (nome, preco, quantidade_estoque) = produto_info; 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.
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 {:#?}.
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.
Resposta
fn main() { // erro: // let config: (&str, u16) = ("localhost", 8080); // config.1 = 8180; let mut config: (&str, u16) = ("localhost", 8080); println!("{:?}", config); config.1 = 8180; 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.
Resposta
fn main () { let player_status: (&str, i32, u8) = ("Hero", 0, 3); let (nome, mut score, vidas) = player_status; println!("Name: {nome}\nScore: {score}\nVidas: {vidas}\n"); score = 1500; println!("Name: {nome}\nScore: {score}\nVidas: {vidas}"); }
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.
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.
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).
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.
Resposta
fn main () { let numeros: [u8; 6] = [1, 2, 4, 8, 16, 32]; println!("{numeros:#?}\n"); let numeros: [u8; 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.
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.
Resposta
fn main () { let mut contador: [u16; 4] = [10, 25, 5, 30]; contador[0] = 12; contador[3] = 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.
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); }
25 - Crie um array mutável pixel_colors: [[u8; 3]; 2] para representar dois pixels, cada um com componentes R, G, B. Inicialize-o como [[255, 0, 0], [0, 255, 0]] (um pixel vermelho, um verde). Modifique o primeiro pixel para ser azul ([0, 0, 255]) e o segundo para ser amarelo ([255, 255, 0]). Imprima o array de pixels.
Resposta
fn main () { let mut pixel_colors: [[u8; 3]; 2] = [[255, 0, 0], [0, 255, 0]]; println!("Vermelho: {:?}", pixel_colors[0]); println!("Verde: {:?}", pixel_colors[1]); // Red > Blue pixel_colors[0][0] = 0; pixel_colors[0][1] = 0; pixel_colors[0][2] = 255; // Green > Yellow pixel_colors[1][0] = 255; pixel_colors[1][1] = 255; pixel_colors[1][2] = 0; println!("Azul: {:?}", pixel_colors[0]); println!("Amarelo: {:?}", pixel_colors[1]); }
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; // adição e atribuição: += num += 1; println!("10 += 1 = {}", num); }
-=
#![allow(unused)] fn main() { let mut num: u8 = 10; // subtração e atribuição: -= num -= 1; println!("10 -= 1 = {}", num); }
*=
#![allow(unused)] fn main() { let mut num: u8 = 10; // multiplicação e atribuição: *= num *= 2; println!("10 *= 2 = {}", num); }
/=
#![allow(unused)] fn main() { let mut num: u8 = 20; // divisão e atribuição: /= num /= 3; println!("20 /= 3 = {}", num); }
%=
#![allow(unused)] fn main() { let mut num: u8 = 6; // resto e atribuição: %= 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.
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.
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.
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.
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.
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!.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Resposta
fn main() { let arr: [i32; 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.
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á?).
Resposta
fn main() { let x: u8 = 1; { let y: u8 = 2; println!("{:?}", x + y); } println!("{:?}", x); // println!("{:?}", y); // Erro: `y` fora 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.
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.
Resposta
fn main() { let num: u8 = 100; println!("{:?}", num); { let num: f32 = 50.; println!("{:?}", num); } println!("{:?}", num); }
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].
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].
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]).
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]).
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 (==).
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 (!=).
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 (>).
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 (<).
Resposta
fn main() { let point_1: u8 = 5; let point_2: u8 = 8; println!("Point-1 < Point-2? {}", point_1 < point_2); }
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 (>=).
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 (<=).
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.
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.
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.
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.
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.
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.
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); }