Rust

Boas Práticas de String vs &str em Rust: Entendendo as Duas Formas de Texto para Times Ágeis

8 min de leitura

Boas Práticas de String vs &str em Rust: Entendendo as Duas Formas de Texto para Times Ágeis

String vs &str em Rust: Entendendo as Duas Formas de Texto O que são String e &str? Em Rust, temos duas formas principais de representar texto: e . A diferença fundamental está em como a memória é gerenciada e onde os dados são armazenados. é um tipo alocado dinamicamente no heap, você é responsável por seu gerenciamento, enquanto é uma referência a uma sequência de bytes UTF-8 válida, geralmente alocada na stack ou na seção de dados do binário. Pense em como um vetor de caracteres que você pode modificar livremente — tem capacidade, comprimento e proprietário. Já é uma visão imutável sobre esses dados: um "empréstimo" que aponta para um local de memória sem poder alterar o conteúdo. Essa distinção é central na filosofia de segurança de memória do Rust. Diferenças de Performance e Memória consome mais memória porque armazena três informações no stack: um ponteiro para os dados no heap, a capacidade e o comprimento atual. A cada

<h2>String vs &amp;str em Rust: Entendendo as Duas Formas de Texto</h2>

<h3>O que são String e &amp;str?</h3>

<p>Em Rust, temos duas formas principais de representar texto: <code>String</code> e <code>&amp;str</code>. A diferença fundamental está em como a memória é gerenciada e onde os dados são armazenados. <code>String</code> é um tipo alocado dinamicamente no heap, você é responsável por seu gerenciamento, enquanto <code>&amp;str</code> é uma referência a uma sequência de bytes UTF-8 válida, geralmente alocada na stack ou na seção de dados do binário.</p>

<p>Pense em <code>String</code> como um vetor de caracteres que você pode modificar livremente — tem capacidade, comprimento e proprietário. Já <code>&amp;str</code> é uma visão imutável sobre esses dados: um &quot;empréstimo&quot; que aponta para um local de memória sem poder alterar o conteúdo. Essa distinção é central na filosofia de segurança de memória do Rust.</p>

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

// String: alocado no heap, mutável, proprietário

let mut s1 = String::from(&quot;Olá&quot;);

s1.push_str(&quot;, Mundo!&quot;);

println!(&quot;{}&quot;, s1); // &quot;Olá, Mundo!&quot;

// &amp;str: referência imutável, literais são na stack/binário

let s2: &amp;str = &quot;Olá, Rust!&quot;;

println!(&quot;{}&quot;, s2); // &quot;Olá, Rust!&quot;

// &amp;str pode vir de uma String

let s3 = String::from(&quot;Teste&quot;);

let referencia: &amp;str = &amp;s3;

println!(&quot;{}&quot;, referencia); // &quot;Teste&quot;

}</code></pre>

<h3>Diferenças de Performance e Memória</h3>

<p><code>String</code> consome mais memória porque armazena três informações no stack: um ponteiro para os dados no heap, a capacidade e o comprimento atual. A cada alocação, pode haver fragmentação de memória. <code>&amp;str</code>, por sua vez, é apenas um ponteiro (64 bits) e um comprimento (64 bits) — 16 bytes no total em arquiteturas de 64 bits — tornando-a muito mais leve para passar entre funções.</p>

<p>Quando você trabalha com strings literais como <code>&quot;Olá&quot;</code>, o compilador as coloca como dados imutáveis no binário (seção <code>.rodata</code>), e <code>&amp;str</code> simplesmente aponta para lá. Não há alocação dinâmica. Use <code>&amp;str</code> como padrão em parâmetros de funções; use <code>String</code> apenas quando você realmente precisa possuir e modificar o texto.</p>

<pre><code class="language-rust">// Não faça isto (ineficiente):

fn processar_texto(texto: String) {

println!(&quot;{}&quot;, texto);

}

// Faça isto:

fn processar_texto(texto: &amp;str) {

println!(&quot;{}&quot;, texto);

}

fn main() {

let s = String::from(&quot;Dados importantes&quot;);

processar_texto(&amp;s); // passa &amp;str, não String

processar_texto(&quot;Literal direto&quot;); // funciona naturalmente

}</code></pre>

<h3>Conversão e Coerção</h3>

<p>Rust permite coerção automática de <code>String</code> para <code>&amp;str</code> em muitos contextos. Quando você passa uma <code>String</code> para uma função que espera <code>&amp;str</code>, o compilador automaticamente converte. Isso é uma das características mais úteis da linguagem — você possui uma <code>String</code>, mas empresta apenas uma visão quando necessário.</p>

<p>Para converter explicitamente, use <code>&amp;string[..]</code> ou <code>&amp;string</code> (quando esperado <code>&amp;str</code>). Para ir na direção oposta, de <code>&amp;str</code> para <code>String</code>, use <code>String::from()</code>, <code>.to_string()</code> ou <code>.to_owned()</code>. Entender essas conversões é crucial para não lutar contra o borrow checker do Rust.</p>

<pre><code class="language-rust">fn saudacao(nome: &amp;str) -&gt; String {

format!(&quot;Olá, {}!&quot;, nome)

}

fn main() {

// Coerção automática: String vira &amp;str

let nome = String::from(&quot;Alice&quot;);

let msg = saudacao(&amp;nome); // &amp;nome é &amp;str

// Conversão explícita

let slice: &amp;str = &amp;nome[0..5]; // &quot;&amp;str&quot; a partir de parte de String

println!(&quot;{}&quot;, slice); // &quot;Alice&quot;

// &amp;str para String

let literai: &amp;str = &quot;Bob&quot;;

let proprietario: String = literai.to_string();

println!(&quot;{}&quot;, proprietario); // &quot;Bob&quot;

}</code></pre>

<h3>Quando Usar Cada Uma</h3>

<p>Use <code>&amp;str</code> em assinaturas de funções como argumento padrão — é ergonômico e eficiente. Use <code>String</code> quando você precisa possuir, modificar ou construir texto dinamicamente, como em loops que concatenam dados ou ao ler de entrada do usuário. Em estruturas de dados, <code>String</code> é a escolha padrão quando você precisa armazenar texto; <code>&amp;str</code> é usada para referências que vivem enquanto seus dados subjacentes existem.</p>

<p>Não tenha medo de ter <code>String</code> em suas estruturas. A cláusula de tempo de vida em <code>&amp;str</code> frequentemente torna o código mais complexo sem benefício real. Reserve <code>&amp;str</code> para quando realmente está apenas emprestando texto, não para quando é responsável por sua existência.</p>

<pre><code class="language-rust">#[derive(Debug)]

struct Pessoa {

nome: String, // proprietária dos dados

email: String,

}

impl Pessoa {

fn new(nome: &amp;str, email: &amp;str) -&gt; Self {

Pessoa {

nome: nome.to_string(),

email: email.to_string(),

}

}

fn apresentar(&amp;self) -&gt; String {

format!(&quot;Sou {} ({})&quot;, self.nome, self.email)

}

}

fn main() {

let pessoa = Pessoa::new(&quot;Carlos&quot;, &quot;carlos@email.com&quot;);

println!(&quot;{}&quot;, pessoa.apresentar());

}</code></pre>

<h2>Conclusão</h2>

<p>Os três pontos essenciais: <strong>primeiro</strong>, <code>String</code> é alocado dinamicamente e mutável, enquanto <code>&amp;str</code> é uma referência imutável e leve; <strong>segundo</strong>, a coerção automática permite passar <code>String</code> onde <code>&amp;str</code> é esperado, facilitando a vida; <strong>terceiro</strong>, use <code>&amp;str</code> em parâmetros de funções e <code>String</code> em propriedades de estruturas e quando você controla o ciclo de vida do dado.</p>

<p>Dominar essa distinção é fundamental em Rust. Investir tempo compreendendo <code>String</code> vs <code>&amp;str</code> elimina frustrações futuras com o borrow checker e resulta em código mais eficiente.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://doc.rust-lang.org/book/ch08-02-strings.html" target="_blank" rel="noopener noreferrer">The Rust Book - String Type</a></li>

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

<li><a href="https://doc.rust-lang.org/reference/types/textual.html" target="_blank" rel="noopener noreferrer">Rust Reference - String</a></li>

<li><a href="https://github.com/rust-lang/rustlings" target="_blank" rel="noopener noreferrer">Rustlings - Move Semantics (Relevant to ownership)</a></li>

<li><a href="https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/" target="_blank" rel="noopener noreferrer">Programming Rust: Fast and Safe Systems Development (2nd Ed.) - Jim Blandy, Jason Orendorff</a></li>

</ul>

Comentários

Mais em Rust

O que Todo Dev Deve Saber sobre Deploy de Aplicações Rust em VPS com Docker e Nginx
O que Todo Dev Deve Saber sobre Deploy de Aplicações Rust em VPS com Docker e Nginx

Preparando sua Aplicação Rust para Produção Antes de fazer deploy, sua aplica...

Boas Práticas de Features e Compilação Condicional em Rust com Cargo para Times Ágeis
Boas Práticas de Features e Compilação Condicional em Rust com Cargo para Times Ágeis

Features em Rust: O Que São e Por Que Importam As features (características)...

Como Usar Enums em Rust: Definição, Variantes e Dados Associados em Produção
Como Usar Enums em Rust: Definição, Variantes e Dados Associados em Produção

Introdução: O Que São Enums em Rust? Enums (enumerações) são um dos pilares d...