Rust

O que Todo Dev Deve Saber sobre Funções, Expressões e o Sistema de Tipos de Rust

8 min de leitura

O que Todo Dev Deve Saber sobre Funções, Expressões e o Sistema de Tipos de Rust

Funções em Rust: Sintaxe, Parâmetros e Retornos Funções são a base da organização de código em Rust. Diferente de muitas linguagens, Rust distingue claramente entre instruções (que não retornam valor) e expressões (que retornam). Uma função é declarada com a palavra-chave , seguida de um nome, parâmetros entre parênteses e, opcionalmente, um tipo de retorno precedido por . Note que em Rust, a última linha sem é uma expressão que retorna seu valor. Se adicionar , torna-se uma instrução que retorna (unit type). Os parâmetros exigem anotação de tipo — isso é obrigatório e não há tipo padrão inferido. Funções podem retornar múltiplos valores usando tuplas, e o compilador força a tratativa correta de tipos, eliminando bugs em tempo de compilação. Closures e Funções Anônimas Closures são funções sem nome que capturam variáveis do escopo envolvente. São poderosas para programação funcional e callbacks. A sintaxe é , onde os tipos podem ser inferidos ou explícitos. Closures implementam os traits ,

<h2>Funções em Rust: Sintaxe, Parâmetros e Retornos</h2>

<p>Funções são a base da organização de código em Rust. Diferente de muitas linguagens, Rust distingue claramente entre instruções (que não retornam valor) e expressões (que retornam). Uma função é declarada com a palavra-chave <code>fn</code>, seguida de um nome, parâmetros entre parênteses e, opcionalmente, um tipo de retorno precedido por <code>-&gt;</code>.</p>

<pre><code class="language-rust">fn add(a: i32, b: i32) -&gt; i32 {

a + b

}

fn greet(name: &amp;str) {

println!(&quot;Olá, {}!&quot;, name);

}

fn main() {

let result = add(5, 3);

println!(&quot;Resultado: {}&quot;, result);

greet(&quot;Maria&quot;);

}</code></pre>

<p>Note que em Rust, a última linha sem <code>;</code> é uma expressão que retorna seu valor. Se adicionar <code>;</code>, torna-se uma instrução que retorna <code>()</code> (unit type). Os parâmetros <strong>exigem anotação de tipo</strong> — isso é obrigatório e não há tipo padrão inferido. Funções podem retornar múltiplos valores usando tuplas, e o compilador força a tratativa correta de tipos, eliminando bugs em tempo de compilação.</p>

<h3>Closures e Funções Anônimas</h3>

<p>Closures são funções sem nome que capturam variáveis do escopo envolvente. São poderosas para programação funcional e callbacks. A sintaxe é <code>|parametros| { corpo }</code>, onde os tipos podem ser inferidos ou explícitos.</p>

<pre><code class="language-rust">fn main() {

let num = 5;

let add_num = |x| x + num; // Captura &#039;num&#039; por referência

println!(&quot;{}&quot;, add_num(3)); // Imprime 8

let multiply = |a: i32, b: i32| -&gt; i32 { a * b };

println!(&quot;{}&quot;, multiply(4, 2)); // Imprime 8

let values = vec![1, 2, 3, 4];

let doubled: Vec&lt;i32&gt; = values.iter().map(|x| x * 2).collect();

println!(&quot;{:?}&quot;, doubled); // [2, 4, 6, 8]

}</code></pre>

<p>Closures implementam os traits <code>Fn</code>, <code>FnMut</code> ou <code>FnOnce</code>, dependendo de como capturam variáveis. <code>Fn</code> captura por referência imutável, <code>FnMut</code> por referência mutável, e <code>FnOnce</code> consome a variável. O compilador infere automaticamente qual trait usar.</p>

<h2>Expressões: O Coração de Rust</h2>

<p>Em Rust, quase tudo é uma expressão. Blocos <code>{}</code>, loops, condicionais — todos retornam valores. Isso diferencia Rust de linguagens como C ou Java, onde essas estruturas são apenas instruções. Uma expressão não termina com ponto-e-vírgula; se terminar, vira uma instrução.</p>

<pre><code class="language-rust">fn main() {

// Expressão if

let number = 5;

let result = if number &gt; 0 {

&quot;positivo&quot;

} else {

&quot;não positivo&quot;

};

println!(&quot;{}&quot;, result); // &quot;positivo&quot;

// Expressão match

let value = 42;

let message = match value {

0 =&gt; &quot;zero&quot;,

1..=10 =&gt; &quot;pequeno&quot;,

_ =&gt; &quot;grande&quot;,

};

println!(&quot;{}&quot;, message); // &quot;grande&quot;

// Bloco como expressão

let x = {

let y = 5;

let z = 6;

y + z // Sem ; retorna o valor

};

println!(&quot;{}&quot;, x); // 11

}</code></pre>

<p>Esse design força o programador a pensar em fluxo de dados de forma mais explícita. A ausência de um <code>;</code> é sintaticamente significativa e intencional, evitando retornos acidentais de <code>()</code>.</p>

<h2>O Sistema de Tipos: Estático, Forte e Inteligente</h2>

<p>Rust possui um sistema de tipos estático e forte, onde cada valor tem um tipo conhecido em tempo de compilação. O sistema é tão rigoroso que evita classes inteiras de bugs. Além dos tipos primitivos (<code>i32</code>, <code>f64</code>, <code>bool</code>, <code>&amp;str</code>), Rust oferece tipos compostos, genéricos e traits para abstraçãoe reutilização.</p>

<h3>Tipos Genéricos e Traits</h3>

<p>Genéricos permitem escrever código reutilizável sem sacrificar segurança de tipo. Traits definem comportamentos compartilhados entre tipos diferentes, funcionando como interfaces.</p>

<pre><code class="language-rust">// Função genérica

fn print_it&lt;T: std::fmt::Display&gt;(val: T) {

println!(&quot;Valor: {}&quot;, val);

}

// Trait customizado

trait Animal {

fn fazer_som(&amp;self) -&gt; &amp;str;

}

struct Cachorro;

struct Gato;

impl Animal for Cachorro {

fn fazer_som(&amp;self) -&gt; &amp;str {

&quot;Au au!&quot;

}

}

impl Animal for Gato {

fn fazer_som(&amp;self) -&gt; &amp;str {

&quot;Miau!&quot;

}

}

fn main() {

print_it(42);

print_it(&quot;Olá&quot;);

let dog = Cachorro;

let cat = Gato;

println!(&quot;{}&quot;, dog.fazer_som()); // Au au!

println!(&quot;{}&quot;, cat.fazer_som()); // Miau!

}</code></pre>

<p>O bound <code>T: std::fmt::Display</code> garante que <code>T</code> implementa o trait <code>Display</code>. Isso permite que o compilador verifique segurança sem runtime overhead. Traits também viabilizam polimorfismo sem herança, seguindo composição sobre herança.</p>

<h3>Option e Result: Tratamento de Erros Seguro</h3>

<p>Rust não possui <code>null</code>; ao invés, usa <code>Option&lt;T&gt;</code> para valores opcionais e <code>Result&lt;T, E&gt;</code> para operações que podem falhar. Isso força o tratamento explícito de casos de erro.</p>

<pre><code class="language-rust">fn divide(a: i32, b: i32) -&gt; Result&lt;i32, String&gt; {

if b == 0 {

Err(&quot;Divisão por zero!&quot;.to_string())

} else {

Ok(a / b)

}

}

fn main() {

match divide(10, 2) {

Ok(resultado) =&gt; println!(&quot;Resultado: {}&quot;, resultado),

Err(erro) =&gt; println!(&quot;Erro: {}&quot;, erro),

}

// Sintaxe &#039;?&#039; para propagação de erro

let result = divide(20, 5).unwrap_or(0);

println!(&quot;{}&quot;, result); // 4

}</code></pre>

<p>O operador <code>?</code> propaga erros automaticamente, reduzindo boilerplate. <code>unwrap()</code> extrai o valor ou panics se for erro; use apenas quando tiver certeza. Essa abordagem torna tratamento de erro explícito e impossível de ignorar.</p>

<h2>Conclusão</h2>

<p>Dominando funções, expressões e o sistema de tipos de Rust, você terá acesso à filosofia central da linguagem: <strong>segurança em tempo de compilação sem sacrificar performance</strong>. Primeira lição: funções e closures são ferramentas poderosas para composição de código. Segunda: expressões, não instruções, levam a um código mais funcional e previsível. Terceira: o sistema de tipos não é um obstáculo — é seu aliado contra bugs, forçando você a pensar claramente sobre possibilidades de erro e fluxo de dados.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://doc.rust-lang.org/book/ch03-03-how-functions-work.html" target="_blank" rel="noopener noreferrer">The Rust Book - Functions</a></li>

<li><a href="https://doc.rust-lang.org/rust-by-example/fn/closures.html" target="_blank" rel="noopener noreferrer">Rust by Example - Closures</a></li>

<li><a href="https://doc.rust-lang.org/book/ch10-02-traits.html" target="_blank" rel="noopener noreferrer">Rust Book - Traits</a></li>

<li><a href="https://doc.rust-lang.org/book/ch09-00-error-handling.html" target="_blank" rel="noopener noreferrer">Error Handling in Rust</a></li>

<li><a href="https://docs.rs/" target="_blank" rel="noopener noreferrer">Official Rust Documentation</a></li>

</ul>

Comentários

Mais em Rust

Boas Práticas de Processos e Subprocessos em Rust com std::process para Times Ágeis
Boas Práticas de Processos e Subprocessos em Rust com std::process para Times Ágeis

Introdução aos Processos em Rust A execução de subprocessos é uma necessidade...

O que Todo Dev Deve Saber sobre Testes Unitários e de Integração em Rust com cargo test
O que Todo Dev Deve Saber sobre Testes Unitários e de Integração em Rust com cargo test

Fundamentos de Testes em Rust Testes em Rust são nativos à linguagem e totalm...

Como Usar Threads em Rust: Criando e Sincronizando Execução Paralela em Produção
Como Usar Threads em Rust: Criando e Sincronizando Execução Paralela em Produção

Criando Threads em Rust A criação de threads em Rust é simples e segura graça...