---
title: "String e \u0026str em Rust"
url: "https://rustlang.com.br/stdlib/string/"
markdown_url: "https://rustlang.com.br/stdlib/string.MD"
description: "Guia completo de String e \u0026str em Rust: criação, manipulação, formatação, conversão e métodos principais com exemplos práticos em português."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# String e &str em Rust

Guia completo de String e &str em Rust: criação, manipulação, formatação, conversão e métodos principais com exemplos práticos em português.


## O que são String e &str

Em Rust, existem dois tipos principais para representar texto: `String` e `&str`. A `String` é um tipo **owned** (proprietário) — ela é alocada no heap, pode crescer ou encolher, e é dona dos seus dados. Já o `&str` é uma **referência imutável** a uma sequência de bytes UTF-8 válida, também chamada de *string slice*. Literais de texto como `"olá"` são do tipo `&str` e ficam embutidos no binário.

A distinção entre `String` e `&str` é um dos conceitos mais importantes em Rust. Use `String` quando precisar de posse sobre o texto (por exemplo, para armazená-lo em uma struct ou retorná-lo de uma função). Use `&str` quando só precisar ler o texto, sem modificá-lo. Ambos os tipos são **sempre UTF-8 válidos**, o que garante segurança ao lidar com texto internacional.

---

## Criando Strings

Existem diversas formas de criar valores `String` e `&str`:

```rust
fn main() {
    // &str — literal de string (armazenado no binário)
    let literal: &str = "Olá, mundo!";

    // String a partir de um literal
    let s1 = String::from("Olá, mundo!");
    let s2 = "Olá, mundo!".to_string();
    let s3: String = "Olá, mundo!".into();

    // String vazia
    let vazia = String::new();

    // String com capacidade pré-alocada
    let mut com_capacidade = String::with_capacity(100);
    com_capacidade.push_str("Texto inicial");

    // A partir de caracteres
    let de_chars: String = vec!['R', 'u', 's', 't'].into_iter().collect();

    // A partir de bytes (pode falhar se não for UTF-8 válido)
    let bytes = vec![79, 108, 195, 161];
    let de_bytes = String::from_utf8(bytes).expect("UTF-8 inválido");
    assert_eq!(de_bytes, "Olá");

    // Repetindo uma string
    let repetida = "ha".repeat(3); // "hahaha"

    // Formatação com format!
    let nome = "Rust";
    let formatada = format!("Eu amo {}!", nome);

    println!("{literal} | {s1} | {de_chars} | {repetida} | {formatada}");
}
```

---

## Tabela de Métodos Principais

| Método | Descrição | Exemplo |
|---|---|---|
| `push_str(&str)` | Adiciona um slice ao final | `s.push_str(" mundo")` |
| `push(char)` | Adiciona um caractere ao final | `s.push('!')` |
| `len()` | Retorna o tamanho em **bytes** | `"café".len()` → `5` |
| `chars().count()` | Retorna o número de **caracteres** | `"café".chars().count()` → `4` |
| `is_empty()` | Verifica se está vazia | `"".is_empty()` → `true` |
| `contains(&str)` | Verifica se contém um trecho | `"Rust".contains("us")` → `true` |
| `starts_with(&str)` | Verifica prefixo | `"Rust".starts_with("Ru")` → `true` |
| `ends_with(&str)` | Verifica sufixo | `"Rust".ends_with("st")` → `true` |
| `replace(&str, &str)` | Substitui todas as ocorrências | `"aabb".replace("a", "x")` → `"xxbb"` |
| `replacen(&str, &str, n)` | Substitui as primeiras `n` ocorrências | `"aaa".replacen("a", "b", 2)` → `"bba"` |
| `trim()` | Remove espaços no início e fim | `" oi ".trim()` → `"oi"` |
| `trim_start()` | Remove espaços no início | `" oi ".trim_start()` → `"oi "` |
| `trim_end()` | Remove espaços no final | `" oi ".trim_end()` → `" oi"` |
| `to_uppercase()` | Converte para maiúsculas | `"rust".to_uppercase()` → `"RUST"` |
| `to_lowercase()` | Converte para minúsculas | `"RUST".to_lowercase()` → `"rust"` |
| `split(&str)` | Divide em partes | `"a,b,c".split(",")` |
| `splitn(n, &str)` | Divide em no máximo `n` partes | `"a,b,c".splitn(2, ",")` |
| `lines()` | Itera sobre linhas | `"a\nb".lines()` |
| `find(&str)` | Posição da primeira ocorrência (em bytes) | `"Rust".find("st")` → `Some(2)` |
| `as_str()` | Converte `String` para `&str` | `s.as_str()` |
| `as_bytes()` | Retorna como slice de bytes | `"abc".as_bytes()` |
| `chars()` | Iterador de caracteres | `"olá".chars()` |
| `bytes()` | Iterador de bytes | `"abc".bytes()` |

---

## Exemplos Práticos

### 1. Concatenando Strings

```rust
fn main() {
    // Usando push_str (mais eficiente para múltiplas operações)
    let mut resultado = String::from("Olá");
    resultado.push_str(", ");
    resultado.push_str("mundo!");
    println!("{resultado}"); // "Olá, mundo!"

    // Usando o operador + (consome o lado esquerdo)
    let saudacao = String::from("Olá");
    let nome = String::from("Rust");
    let mensagem = saudacao + ", " + &nome + "!";
    // Nota: saudacao foi movida, não pode mais ser usada
    println!("{mensagem}"); // "Olá, Rust!"

    // Usando format! (não consome nenhum valor)
    let cidade = "São Paulo";
    let estado = "SP";
    let local = format!("{cidade} - {estado}");
    println!("{local}"); // "São Paulo - SP"

    // Juntando um iterador com join
    let partes = vec!["Rust", "é", "incrível"];
    let frase = partes.join(" ");
    println!("{frase}"); // "Rust é incrível"
}
```

### 2. Processando Texto Linha por Linha

```rust
fn contar_palavras(texto: &str) -> Vec<(&str, usize)> {
    use std::collections::HashMap;

    let mut contagem: HashMap<&str, usize> = HashMap::new();
    for palavra in texto.split_whitespace() {
        *contagem.entry(palavra).or_insert(0) += 1;
    }

    let mut resultado: Vec<_> = contagem.into_iter().collect();
    resultado.sort_by(|a, b| b.1.cmp(&a.1));
    resultado
}

fn main() {
    let texto = "rust é rápido rust é seguro rust é produtivo";
    let contagem = contar_palavras(texto);

    for (palavra, qtd) in &contagem {
        println!("{palavra}: {qtd}");
    }
    // rust: 3
    // é: 3
    // rápido: 1
    // seguro: 1
    // produtivo: 1
}
```

### 3. Validando e Limpando Input do Usuário

```rust
fn limpar_email(input: &str) -> Option<String> {
    let email = input.trim().to_lowercase();

    if email.is_empty() {
        return None;
    }

    if !email.contains('@') || !email.contains('.') {
        return None;
    }

    let partes: Vec<&str> = email.split('@').collect();
    if partes.len() != 2 || partes[0].is_empty() || partes[1].is_empty() {
        return None;
    }

    Some(email)
}

fn main() {
    let entradas = vec![
        "  Usuario@Email.COM  ",
        "invalido",
        "",
        "valido@exemplo.com.br",
    ];

    for entrada in entradas {
        match limpar_email(entrada) {
            Some(email) => println!("Válido: {email}"),
            None => println!("Inválido: '{entrada}'"),
        }
    }
}
```

### 4. Trabalhando com UTF-8 e Caracteres Especiais

```rust
fn main() {
    let texto = "Café é bom! 🦀";

    // len() retorna bytes, não caracteres!
    println!("Bytes: {}", texto.len());          // 19
    println!("Caracteres: {}", texto.chars().count()); // 15

    // Iterando sobre caracteres
    for (i, c) in texto.chars().enumerate() {
        if !c.is_ascii() {
            println!("Caractere não-ASCII na posição {i}: '{c}'");
        }
    }

    // Fatiando com segurança (por índice de byte)
    // CUIDADO: fatiar no meio de um caractere multi-byte causa panic!
    let cafe = &texto[0..5]; // "Café" (é ocupa 2 bytes)
    println!("{cafe}");

    // Forma segura de pegar os primeiros N caracteres
    let primeiros_4: String = texto.chars().take(4).collect();
    println!("{primeiros_4}"); // "Café"

    // Verificando se uma string é ASCII
    println!("É ASCII? {}", "hello".is_ascii());  // true
    println!("É ASCII? {}", "café".is_ascii());    // false
}
```

### 5. Conversões entre Tipos

```rust
fn main() {
    // Número para String
    let n: i32 = 42;
    let s = n.to_string();
    let s2 = format!("{n:06}"); // "000042" (padding com zeros)

    // String para número
    let numero: i32 = "42".parse().expect("Não é um número");
    let pi: f64 = "3.14".parse().expect("Não é um float");

    // String para &str
    let minha_string = String::from("olá");
    let slice: &str = &minha_string; // coerção automática
    let slice2: &str = minha_string.as_str();

    // &str para String
    let meu_slice: &str = "olá";
    let string: String = meu_slice.to_string();
    let string2: String = String::from(meu_slice);

    // Vec<u8> para String
    let bytes: Vec<u8> = vec![82, 117, 115, 116];
    let texto = String::from_utf8(bytes).unwrap();
    assert_eq!(texto, "Rust");

    // String para Vec<u8>
    let bytes_de_volta: Vec<u8> = texto.into_bytes();

    println!("{s} {s2} {numero} {pi} {slice} {string} {}",
             String::from_utf8(bytes_de_volta).unwrap());
}
```

---

## Dicas de Performance e Armadilhas

1. **`len()` vs `chars().count()`**: O método `len()` retorna o número de **bytes**, não de caracteres. Para texto com acentos ou emojis, use `chars().count()`. Exemplo: `"café".len()` retorna `5`, mas `"café".chars().count()` retorna `4`.

2. **Pré-aloque com `with_capacity`**: Se você sabe o tamanho aproximado da string final, use `String::with_capacity(n)` para evitar realocações. Isso é especialmente útil em loops.

3. **Evite concatenação com `+` em loops**: Cada uso do operador `+` pode realocar memória. Prefira `push_str()` em uma `String` mutável ou use `format!` para construções simples.

4. **Fatiar strings UTF-8 com cuidado**: Indexar com `[i..j]` funciona em bytes, não caracteres. Fatiar no meio de um caractere multi-byte causa **panic em tempo de execução**. Use `chars()` para iterar com segurança.

5. **`&str` em parâmetros de função**: Sempre que possível, aceite `&str` ao invés de `&String` nos parâmetros de função. Graças à coerção `Deref`, tanto `String` quanto `&str` podem ser passados.

6. **Use `Cow<str>` para flexibilidade**: Quando uma função às vezes precisa retornar uma string emprestada e às vezes uma string nova, use [`Cow<str>`](/stdlib/cow/) para evitar clonagens desnecessárias.

---

## Veja Também

- [Formatar Strings em Rust](/receitas/formatar-strings/) — receitas práticas de formatação
- [Dividir Strings em Rust](/receitas/dividir-string/) — padrões para split e parsing
- [Vec\<T\>: Vetor Dinâmico](/stdlib/vec/) — para quando precisar de coleções de strings
- [Cow\<T\>: Clone on Write](/stdlib/cow/) — para evitar alocações desnecessárias com strings
- [Slices (&[T])](/stdlib/slice/) — conceito similar aplicado a sequências genéricas
- [Iterator Trait](/stdlib/iterator/) — para processar caracteres e linhas de texto
- [Cheatsheet Rust](/cheatsheet/) — referência rápida de sintaxe
- [Documentação oficial — std::string::String](https://doc.rust-lang.org/std/string/struct.String.html)
- [Documentação oficial — str](https://doc.rust-lang.org/std/primitive.str.html)
