Rust: Operadores e expressões em Rust
Última atualização: 2026-08-26
No Rust, quase tudo é uma expressão — inclusive
ifematch.
Compreender a diferença entre expressões (que retornam um valor) e instruções (que não retornam um valor) é fundamental para escrever código conciso em Rust.
1. O que você vai aprender
- Operadores aritméticos:
+ - * / % - Operadores de comparação:
== != < > <= >= - Operadores lógicos:
&& || ! - Operadores bit a bit:
& | ^ << >> - A diferença entre expressões e instruções
- Precedência dos operadores
2. A história de uma caixa
(1) Frustração: eu sempre cometo erros ao calcular descontos
Tom é gerente de uma loja de roupas e, todos os dias, precisa calcular vários descontos:
- Compre 2 itens e ganhe 20% de desconto; compre 3 itens e ganhe 30% de desconto
- Economize 50 em pedidos de 500 ou mais
- Os membros têm um desconto adicional de 5%
- Eu calculei mal a ordem ao combinar os descontos, o que fez com que as contas não fechassem no final do mês, resultando em um prejuízo de 500 yuans.
“Seria ótimo se houvesse uma calculadora que pudesse realizar cálculos automaticamente na ordem correta...”
(2) O esquema de expressões do Rust
fn main() {
let price: f64 = 299.0; // A piece of clothing 299 yuan
let quantity: i32 = 3; // Bought 3 items
let is_member: bool = true; // Is a member
// Calculate all discounts with a single expression
let total = (price * quantity as f64) // Original Price
* if quantity >= 3 { 0.7 } else { 0.9 } // Volume Discount
* if is_member { 0.95 } else { 1.0 }; // Member Discounts
println!("Original Price: {:.2} yuan", price * quantity as f64);
println!("Price after discount: {:.2} yuan", total);
println!("Save: {:.2} yuan", price * quantity as f64 - total);
}
No Rust,
ifé uma expressão por si só e pode retornar um valor diretamente. Isso permite que o cálculo do desconto seja expresso como uma única cadeia de expressões, eliminando o risco de erros.
3. Lista de operadores
graph TB
A[Rust Operators] --> B[Arithmetic: + - * / %]
A --> C[Comparison: == != < > <= >=]
A --> D[Logic: && || !]
A --> E[Bitwise Operations: & | ^ << >>]
A --> F[Assignment: = += -= *= /=]
(1) Operadores aritméticos
| Operador | Exemplo | Descrição |
|---|---|---|
+ |
a + b |
Adição |
- |
a - b |
Subtração |
* |
a * b |
Multiplicação |
/ |
a / b |
Divisão (truncamento inteiro) |
% |
a % b |
restante |
- |
-a |
Negação (unária) |
A divisão de inteiros resulta em truncamento:
5 / 2 = 2(não 2,5). Para obter um resultado em ponto flutuante, é preciso usar um tipo de ponto flutuante:5.0 / 2.0 = 2.5.
(2) Operadores de comparação
Todos os operadores de comparação retornam o tipo bool: true ou false.
let a = 10;
let b = 20;
println!("{}", a == b); // false
println!("{}", a != b); // true
println!("{}", a < b); // true
(3) Operadores lógicos
| Operador | Nome | Exemplo | Descrição |
|---|---|---|---|
&& |
Operador lógico AND | a && b |
É verdadeiro somente se ambos forem verdadeiros (curto-circuito) |
| ` | ` | OU lógico | |
! |
NÃO lógico | !a |
Inverter |
Avaliação por curto-circuito:
&&— se o lado esquerdo for falso, o lado direito não é avaliado;||— se o lado esquerdo for verdadeiro, o lado direito não é avaliado. Isso pode ser usado no padrão “verificar antes de acessar”.
(4) Operadores bit a bit
| Operador | Nome | Exemplo | Descrição |
|---|---|---|---|
& |
AND bit a bit | a & b |
É igual a 1 somente se todos os bits correspondentes forem 1 |
| ` | ` | OR bit a bit | `a |
^ |
XOR bit a bit | a ^ b |
É igual a 1 somente se os bits correspondentes forem diferentes |
<< |
Deslocamento para a esquerda | a << n |
Deslocamento para a esquerda em n bits (equivalente à multiplicação por 2^n) |
>> |
Deslocamento para a direita | a >> n |
Deslocamento para a direita em n bits (equivalente à divisão por 2^n) |
4. Expressões e instruções
(1) Principais diferenças
| Conceito | Definição | Exemplo |
|---|---|---|
| Expressão | Possui um valor de retorno | 5 + 3 retorna 8, if true { 1 } else { 0 } retorna 1 |
| Instrução | Sem valor de retorno | let x = 5; Sem valor de retorno, fn foo() {} Sem valor de retorno |
No Rust, os pontos-e-vírgulas determinam se algo é uma expressão ou uma instrução:
fn main() {
let y = {
let x = 3;
x + 1 // No semicolons -- This is an expression, Returns 4
}; // End of semicolon let Statement
println!("y the value: {}", y); // 4
}
(2) Expressões em bloco
{} O bloco de código dentro do bloco pode ser uma expressão; se a última linha não terminar com um ponto-e-vírgula, ele retorna um valor:
let result = {
let a = 2;
let b = 3;
a * b // No semicolons, This expression returns 6
};
5. Exemplos de operadores
▶ Exemplo 1: Operações aritméticas e tipos (Dificuldade ⭐)
// ============================================
// Demonstration of Arithmetic Operators——Note: Truncation in integer division
// ============================================
fn main() {
let a = 10;
let b = 3;
println!("Addition: {} + {} = {}", a, b, a + b);
println!("Subtraction: {} - {} = {}", a, b, a - b);
println!("Multiplication: {} * {} = {}", a, b, a * b);
println!("Integer Division: {} / {} = {} (Truncation)", a, b, a / b);
println!("Floating-Point Division: {} / {} = {:.2}", a as f64, b as f64, a as f64 / b as f64);
println!("Modulo: {} % {} = {}", a, b, a % b);
}
Resultado:
Addition: 10 + 3 = 13
Subtraction: 10 - 3 = 7
Multiplication: 10 * 3 = 30
Integer Division: 10 / 3 = 3 (Truncation)
Floating-Point Division: 10 / 3 = 3.33
Modulo: 10 % 3 = 1
asAs palavras-chave são usadas para conversão de tipos.a as f64Converta o número inteiro em um número de ponto flutuante antes de realizar a divisão para obter um resultado em ponto flutuante.
▶ Exemplo 2: Avaliação por curto-circuito de operações lógicas (Dificuldade: ⭐⭐)
// ============================================
// Short-Circuit Evaluation of Logical Operators
// ============================================
fn main() {
let age = 17;
let has_id = true;
// && Short Circuit: If the left is false, the right side is not executed
let can_buy = age >= 18 && has_id;
println!("Available for purchase (&&): {}", can_buy); // false (Since the left side is already false)
// || Short Circuit: If the left is true, the right side is not executed
let is_ok = true || (expensive_check());
println!("(|| Short Circuit, The right side will not be executed): {}", is_ok);
}
fn expensive_check() -> bool {
println!("This function will not be executed!");
true
}
Resultado:
Available for purchase (&&): false
(|| Short Circuit, The right side will not be executed): true
A avaliação por curto-circuito é uma importante técnica de otimização de desempenho — ela posiciona as verificações de baixo custo à esquerda e as de alto custo à direita, a fim de evitar cálculos desnecessários.
▶ Exemplo 3: Valores de retorno de blocos de expressão (Dificuldade ⭐⭐)
// ============================================
// Using Expression Blocks to Implement Concise Assignments with Complex Conditions
// ============================================
fn main() {
let score = 85;
let grade = {
if score >= 90 {
"A"
} else if score >= 80 {
"B"
} else if score >= 70 {
"C"
} else if score >= 60 {
"D"
} else {
"F"
}
}; // Note: The entire if-else chain is an expression, End with a semicolon let Statement
println!("Score: {}, Level: {}", score, grade);
// Alternatives to Ternary Operations: Use if Expression
let is_pass = if score >= 60 { "passed" } else { "failed" };
println!("Result: {}", is_pass);
}
Resultado:
Score: 85, Level: B
Result: passed
O Rust não possui um operador ternário (
condition ? a : b), masifé uma expressão por si só e permite obter o mesmo resultado com maior legibilidade.
▶ Exemplo 4: Operações bit a bit na prática — Indicadores de permissão e mistura de cores (Dificuldade ⭐⭐)
// ============================================
// Bitwise Operations in Practice:File Permissions and RGB Color Manipulation
// ============================================
fn main() {
let read_perm: u8 = 0b100; // 4
let write_perm: u8 = 0b010; // 2
let exec_perm: u8 = 0b001; // 1
let user_perm = read_perm | write_perm;
println!("User Permissions: {:03b} (Read+Write)", user_perm);
let full_perm = read_perm | write_perm | exec_perm;
println!("Full Permissions: {:03b} (Read+Write+Execute)", full_perm);
let can_read = (user_perm & read_perm) != 0;
let can_exec = (user_perm & exec_perm) != 0;
println!("User-readable: {}, Executable: {}", can_read, can_exec);
let no_write = user_perm & !write_perm;
println!("Remove Write Permissions: {:03b}", no_write);
let toggled = user_perm ^ exec_perm;
println!("Toggle the execution bit: {:03b}", toggled);
let red: u32 = 0xFF0000;
let green: u32 = 0x00FF00;
let blue: u32 = 0x0000FF;
let yellow = red | green;
let white = red | green | blue;
println!("\nRed: {:06X}", red);
println!("Yellow (Red|Green): {:06X}", yellow);
println!("White (Red|Green|Blue): {:06X}", white);
let pixel: u32 = 0xFF8040;
let r = (pixel >> 16) & 0xFF;
let g = (pixel >> 8) & 0xFF;
let b = pixel & 0xFF;
println!("\nPixel #FF8040 → R={}, G={}, B={}", r, g, b);
let shift_val: u8 = 1;
println!("\n1 << 0 = {}", shift_val << 0);
println!("1 << 1 = {}", shift_val << 1);
println!("1 << 2 = {}", shift_val << 2);
println!("1 << 3 = {}", shift_val << 3);
}
Resultado:
User Permissions: 110 (Read+Write)
Full Permissions: 111 (Read+Write+Execute)
User-readable: true, Executable: false
Remove Write Permissions: 100
Toggle the execution bit: 111
Red: FF0000
Yellow (Red|Green): FFFF00
White (Red|Green|Blue): FFFFFF
Pixel #FF8040 → R=255, G=128, B=64
1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
As operações bit a bit são extremamente comuns na programação de sistemas: para gerenciamento de permissões, use
|para mesclar,¶ verificar e& !para remover; para cores, use|para misturar e>>+¶ extrair canais;<<equivale a multiplicar por uma potência de 2.
▶ Exemplo 5: Precedência de operadores e expressões compostas (Dificuldade ⭐⭐⭐)
// ============================================
// Operator Precedence in Practice + Compound Assignment Operator
// ============================================
fn main() {
println!("=== Operator Precedence ===");
let a = 2 + 3 * 4;
println!("2 + 3 * 4 = {} (Multiply First, Then Add)", a);
let b = (2 + 3) * 4;
println!("(2 + 3) * 4 = {} (Parentheses Take Precedence)", b);
let c = 10 - 6 / 2;
println!("10 - 6 / 2 = {} (Multiply First, Then Subtract)", c);
let d = true && false || true;
println!("true && false || true = {} (&& Take precedence over ||)", d);
let e = true || false && false;
println!("true || false && false = {} (&& Take precedence over ||)", e);
println!("\n=== Compound Assignment Operator ===");
let mut score: i32 = 100;
score += 20;
println!("score += 20 → {}", score);
score -= 30;
println!("score -= 30 → {}", score);
score *= 2;
println!("score *= 2 → {}", score);
score /= 7;
println!("score /= 7 → {}", score);
score %= 3;
println!("score %= 3 → {}", score);
println!("\n=== Chain Comparison(Using logical operators)===");
let x = 50;
let in_range = x >= 0 && x <= 100;
let out_range = x < 0 || x > 100;
println!("x={}, in [0,100]: {}, Out of range: {}", x, in_range, out_range);
let charlie_score = 75;
let bob_score = 88;
let both_passed = charlie_score >= 60 && bob_score >= 60;
let any_excellent = charlie_score >= 90 || bob_score >= 90;
println!("Both passed: {}, Someone excellent: {}", both_passed, any_excellent);
}
Resultado:
=== Operator Precedence ===
2 + 3 * 4 = 14 (Multiply First, Then Add)
(2 + 3) * 4 = 20 (Parentheses Take Precedence)
10 - 6 / 2 = 7 (Multiply First, Then Subtract)
true && false || true = true (&& Take precedence over ||)
true || false && false = true (&& Take precedence over ||)
=== Compound Assignment Operator ===
score += 20 → 120
score -= 30 → 90
score *= 2 → 180
score /= 7 → 25
score %= 3 → 1
=== Chain Comparison(Using logical operators)===
x=50, in [0,100]: true, Out of range: false
Both passed: true, Someone excellent: false
Prioridade dos operadores, da mais alta à mais baixa:
* / %→+ -→ operadores de comparação →&&→||. Em caso de dúvida, use parênteses; a legibilidade do código é mais importante do que a “concisão”.
❓ Perguntas Frequentes
P: A que é igual 5 / 2 em Rust? R: É igual a 2 (divisão inteira com truncamento). Para obter 2,5, é preciso escrever
5.0 / 2.0ou5 as f64 / 2 as f64. Isso é igual ao que acontece em C, mas diferente do Python 3 (no Python 3,/retorna um número de ponto flutuante).
P: O Rust possui os operadores ++ e --? R: Não. O Rust não possui, intencionalmente,
i++ei--, pois eles podem facilmente causar confusão nas expressões. Usei += 1oui = i + 1em vez disso.
P: Qual é a diferença entre && e &? R: && é um AND lógico (de curto-circuito), e & é um AND bit a bit (sem curto-circuito).
true && falseretornafalse, e5 & 3retorna1. Os tipos também são diferentes: os operandos em ambos os lados de && sãobool, enquanto os de ambos os lados de & são inteiros.
P: Como posso distinguir entre expressões e instruções? R: Verifique se há um ponto-e-vírgula no final. Um ponto-e-vírgula indica uma instrução (que não retorna um valor); a ausência de ponto-e-vírgula indica uma expressão (que retorna um valor). Em Rust, o ponto-e-vírgula funciona como um interruptor que “absorve” o valor de retorno.
P: Quais são as armadilhas da conversão de tipos com
as? R:astrunca os dados silenciosamente, sem relatar um erro. Por exemplo,300_u16 as u8retorna 44 (bits de ordem superior truncados), enquanto-1_i32 as u32retorna 4294967295 (reinterpretação do padrão de bits). Para uma conversão segura, recomenda-se usartry_into()(que retornaResult); useassomente quando tiver certeza de que nenhum dado será perdido.
📖 Resumo
- O Rust possui quatro tipos de operadores: aritméticos, de comparação, lógicos e bit a bit; a maioria deles é semelhante aos encontrados em outras linguagens.
- A divisão de inteiros resulta em truncamento; use
aspara converter para divisão em ponto flutuante - Os operadores lógicos
&&e||apresentam um comportamento de avaliação por curto-circuito - Expressões têm valores de retorno, enquanto instruções não têm — o ponto-e-vírgula faz toda a diferença.
ifé uma expressão por si só e pode ser usada como substituto do operador ternário em outras linguagens O Rust não possui++/--; use+= 1/-= 1em vez disso.
📝 Exercícios
- Dificuldade ⭐: Escreva um programa que utilize a conversão
aspara converteri32do tipo5e2emf64e que gere5 / 2 = 2.5como resultado. - Dificuldade ⭐⭐: Defina uma variável
x = 5, use um bloco de expressão{ x + 1 }para atribuir um valor aye determine sexainda está acessível fora do bloco de expressão. - Dificuldade ⭐⭐⭐: Implemente uma função
fn is_even(n: i32) -> boolusando operadores bit a bit, na qual você deve utilizar&operações bit a bit (e não%) para determinar a paridade.