Curso gratuito de Rust: A linguagem mais amada
Funções e Controle de Fluxo (if/else, loops)
Aprenda sobre funções e controle de fluxo (if/else, loops)
🚀 Funções e Controle de Fluxo em Rust
Olá, futuros Rustaceans! 👋 Nesta aula, vamos mergulhar em dois pilares fundamentais de qualquer linguagem de programação: Funções e Controle de Fluxo. São eles que nos permitem organizar nosso código, reutilizá-lo e tomar decisões baseadas em diferentes condições. Em Rust, esses conceitos têm algumas nuances interessantes que os tornam poderosos e expressivos.
Vamos começar nossa jornada! 🛤️
1. Funções: O Coração Reutilizável do Seu Código ❤️
Funções são blocos de código que executam uma tarefa específica e podem ser chamados várias vezes ao longo do programa. Elas nos ajudam a organizar o código, torná-lo mais legível e evitar repetições (o famoso princípio DRY - Don't Repeat Yourself).
1.1. Definição e Chamada de Funções
Em Rust, definimos funções usando a palavra-chave fn.
fn main() {
println!("Olá do Rust!"); // Chamando uma função nativa
minha_primeira_funcao(); // Chamando nossa função personalizada
}
fn minha_primeira_funcao() {
println!("Esta é a minha primeira função personalizada!");
}Explicação:
fn: Palavra-chave para declarar uma função.main: É a função especial que é o ponto de entrada de todo programa Rust.minha_primeira_funcao: É o nome que demos à nossa função.(): Parênteses após o nome da função indicam que ela não recebe nenhum parâmetro (argumento).{}: Chaves delimitam o corpo da função, onde o código a ser executado reside.
1.2. Parâmetros e Argumentos 🤝
Funções podem receber valores, chamados de parâmetros, que são variáveis declaradas na assinatura da função. Quando chamamos a função, passamos argumentos para esses parâmetros.
fn main() {
imprimir_valor(5);
imprimir_soma(10, 20);
}
fn imprimir_valor(x: i32) { // 'x' é o parâmetro, do tipo i32
println!("O valor é: {}", x);
}
fn imprimir_soma(a: i32, b: i32) { // 'a' e 'b' são parâmetros, ambos i32
println!("A soma de {} e {} é: {}", a, b, a + b);
}Explicação:
- Em Rust, você deve declarar o tipo de cada parâmetro na assinatura da função. Isso é uma parte crucial da segurança de tipos do Rust.
x: i32significa que o parâmetroxé do tipo inteiro de 32 bits.
1.3. Valores de Retorno ↩️
Funções podem retornar um valor para o código que as chamou. Em Rust, o tipo de retorno é especificado após uma seta ->. O valor de retorno é a última expressão no corpo da função, ou você pode usar a palavra-chave return.
fn main() {
let resultado_soma = somar(5, 7);
println!("A soma é: {}", resultado_soma);
let resultado_multiplicacao = multiplicar(4, 3);
println!("A multiplicação é: {}", resultado_multiplicacao);
}
fn somar(a: i32, b: i32) -> i32 { // -> i32 indica que a função retorna um i32
a + b // Esta é uma expressão. O valor dela é retornado implicitamente.
}
fn multiplicar(x: i32, y: i32) -> i32 {
return x * y; // Uso explícito de 'return'. Um ponto e vírgula é necessário aqui.
}Explicação:
- A última linha de uma função sem ponto e vírgula é considerada uma expressão e seu valor é automaticamente retornado.
- Se você quiser retornar explicitamente antes do final da função ou em uma condição, use
return <valor>;. Note o ponto e vírgula. - Funções que não retornam um valor (como
mainouimprimir_valor) implicitamente retornam a "unidade"(), que é um tipo vazio.
1.4. Expressões vs. Declarações (Statements) 🧐
Rust é uma linguagem baseada em expressões. Isso significa que a maioria das coisas que você escreve é uma expressão que avalia um valor.
- Declarações (Statements): Instruções que realizam uma ação, mas não retornam um valor. Ex:
let y = 6;oufn foo() {}. - Expressões: Avaliam um valor. Ex:
5 + 6,x,if condition { 5 } else { 6 }.
fn main() {
let y = 6; // Declaração: 'let y = 6;' é uma declaração.
// '6' é uma expressão.
let x = { // Este bloco de código é uma expressão!
let z = 3; // Declaração dentro do bloco
z + 1 // Expressão: o valor de 'z + 1' (4) é o valor do bloco
};
println!("O valor de x é: {}", x); // Saída: O valor de x é: 4
}Exemplo Oficial (Adaptado do The Rust Programming Language Book):
// Exemplo de conversão de Fahrenheit para Celsius
fn main() {
let fahrenheit = 77.0;
let celsius = fahrenheit_para_celsius(fahrenheit);
println!("{}°F é igual a {}°C", fahrenheit, celsius);
let celsius_novo = celsius_para_fahrenheit(25.0);
println!("25°C é igual a {}°F", celsius_novo);
}
fn fahrenheit_para_celsius(temp_f: f64) -> f64 {
(temp_f - 32.0) * 5.0 / 9.0
}
fn celsius_para_fahrenheit(temp_c: f64) -> f64 {
(temp_c * 9.0 / 5.0) + 32.0
}2. Controle de Fluxo: Tomando Decisões e Repetindo Ações 🚦
O controle de fluxo permite que seu programa tome decisões sobre qual código executar e quantas vezes repetir uma ação.
2.1. Condicionais com if/else ❓
O construto if permite executar um bloco de código apenas se uma condição for verdadeira. Em Rust, if é uma expressão, o que significa que ele avalia um valor.
fn main() {
let numero = 7;
if numero < 5 {
println!("A condição é verdadeira: o número é menor que 5.");
} else {
println!("A condição é falsa: o número não é menor que 5.");
}
// if/else if/else
let outro_numero = 6;
if outro_numero % 4 == 0 {
println!("Número é divisível por 4");
} else if outro_numero % 3 == 0 {
println!("Número é divisível por 3");
} else if outro_numero % 2 == 0 {
println!("Número é divisível por 2");
} else {
println!("Número não é divisível por 4, 3 ou 2");
}
// Usando if em uma declaração 'let' (porque if é uma expressão!)
let condicao = true;
let valor = if condicao {
5
} else {
6
}; // Note que ambos os ramos devem retornar o mesmo tipo!
println!("O valor é: {}", valor); // Saída: O valor é: 5
// Exemplo de erro: tipos diferentes
// let valor_erro = if condicao {
// 5
// } else {
// "seis" // Erro! Tipos incompatíveis: i32 vs &str
// };
}Explicação:
- A condição em
ifnão precisa de parênteses, mas o bloco de códigoifdeve ter chaves{}. - A condição deve ser do tipo
bool. Rust não tenta converter tipos não-booleanos para booleanos. - Quando usado em
let, ambos os blocosifeelsedevem retornar valores do mesmo tipo.
2.2. Repetições com Loops 🔄
Rust oferece três tipos de loops: loop, while e for.
2.2.1. loop: O Loop Infinito (e Retorno de Valores)
O loop é o mais simples e cria um loop infinito. Você deve usar break para sair dele. Ele também pode retornar um valor!
fn main() {
let mut contador = 0;
let resultado = loop {
contador += 1;
if contador == 10 {
break contador * 2; // 'break' pode retornar um valor
}
};
println!("O resultado do loop é: {}", resultado); // Saída: 20
}Explicação:
loopcria um ciclo que se repetirá indefinidamente até que umbreakseja encontrado.break: Sai do loop imediatamente. Pode ser usado para retornar um valor do loop.
2.2.2. while: O Loop Condicional
O while executa um bloco de código enquanto uma condição for verdadeira.
fn main() {
let mut numero = 3;
while numero != 0 {
println!("{}!", numero);
numero -= 1;
}
println!("FIM!");
}Explicação:
- A condição é avaliada antes de cada iteração. Se for verdadeira, o bloco é executado. Se for falsa, o loop termina.
2.2.3. for: Iterando sobre Coleções (e Ranges) 🎯
O for loop é usado para iterar sobre os elementos de uma coleção ou um range de números. É o loop mais comum em Rust.
fn main() {
// Iterando sobre um array
let a = [10, 20, 30, 40, 50];
for elemento in a.iter() {
println!("O valor é: {}", elemento);
}
// Iterando sobre um range (exclusivo no final)
for numero in 1..4 { // De 1 até 3 (4 é exclusivo)
println!("Número: {}", numero);
}
// Iterando sobre um range (inclusivo no final)
for numero in 1..=4 { // De 1 até 4 (4 é inclusivo)
println!("Número (inclusivo): {}", numero);
}
// Exemplo de contagem regressiva com for e range reverso
for numero in (1..4).rev() { // De 3 até 1
println!("{}!", numero);
}
println!("FIM!");
}Explicação:
a.iter(): Cria um iterador sobre os elementos do arraya.1..4: Cria um range de números de 1 (inclusive) a 4 (exclusive).1..=4: Cria um range de números de 1 (inclusive) a 4 (inclusive)..rev(): Inverte a ordem do iterador.
2.2.4. Labels de Loop: Controlando Loops Aninhados 🏷️
Você pode usar labels com loops para especificar qual loop você quer break ou continue em loops aninhados.
fn main() {
let mut contador = 0;
'loop_externo: loop { // Definindo um label para o loop externo
println!("Contador externo: {}", contador);
let mut contador_interno = 0;
'loop_interno: loop { // Definindo um label para o loop interno
println!(" Contador interno: {}", contador_interno);
if contador_interno == 2 {
break 'loop_interno; // Quebra apenas o loop interno
}
contador_interno += 1;
}
if contador == 1 {
break 'loop_externo; // Quebra o loop externo
}
contador += 1;
}
println!("Fim de todos os loops.");
}Explicação:
'nome_do_label: loop { ... }permite nomear um loop.break 'nome_do_label;oucontinue 'nome_do_label;controlam o loop específico com aquele label.
3. Integração com Múltiplas Tecnologias (N/A) 🚫
Esta aula foca nos fundamentos da linguagem Rust. A integração com múltiplas tecnologias (como Express.js ou Better-Auth) não se aplica a este tópico específico, pois estamos explorando as funcionalidades básicas e intrínsecas da própria linguagem Rust.
4. Exercícios/Desafios (N/A) 📝
Esta aula é de natureza teórica, focada na explicação conceitual. A seção de exercícios e desafios será abordada em aulas práticas ou projetos futuros, onde você terá a oportunidade de aplicar esses conhecimentos!
5. Resumo e Próximos Passos 🚀
Nesta aula, cobrimos os conceitos essenciais de funções e controle de fluxo em Rust:
- Funções (
fn): Como definir, chamar, passar parâmetros e retornar valores. Entendemos a distinção entre expressões e declarações. - Condicionais (
if/else): Como tomar decisões no seu código, e a característica deifser uma expressão em Rust. - Loops (
loop,while,for): Diferentes maneiras de repetir ações, incluindo loops infinitos, condicionais e iteração sobre coleções, além do uso de labels.
Com esses fundamentos, você já pode começar a escrever programas Rust mais estruturados e dinâmicos!
Próximos Passos: No próximo módulo, vamos explorar os tipos de dados compostos, como tuplas e arrays, e como Rust gerencia a memória com o conceito de Ownership. Prepare-se para mais conceitos poderosos! 💪