Como transformar Option<String> em Option<&str> em Rust sem dor

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que você está aqui? Seja honesto

\n\n

Você está programando em Rust e de repente encontra uma parede. Você tem um Option<String> — algum valor que pode ou não existir. E a função que você quer chamar exige Option<&str>. E o compilador olha para você com reprovação, mostrando um erro que dá vontade de fechar o notebook e ir tomar um chá.

\n\n

Não se preocupe. Essa situação é tão comum que a pergunta "Converting from Option<String> to Option<&str>" no Stack Overflow já teve milhares de visualizações. Você não está sozinho.

\n\n

Neste artigo, vamos entender por que essa conversão gera tantas dúvidas e — o mais importante — como fazê-la corretamente. Sem mágica, sem cópias desnecessárias de memória, com total compreensão do que acontece nos bastidores.

\n\n

O problema: por que não podemos simplesmente converter?

\n\n

Primeiro, uma olhada rápida nos tipos.

\n\n
    \n
  • String — é um tipo proprietário. Ele possui os dados no heap e é responsável por liberá-los.
  • \n
  • &str — é uma referência a uma fatia de string. Ele empresta os dados, sem possuí-los.
  • \n
\n\n

E é aí que a diversão começa. Option<String> é possivelmente uma string que você possui. Option<&str> é possivelmente uma referência a uma string.

\n\n

O problema é que você não pode simplesmente pegar uma referência ao valor dentro de um Option e passá-la para fora, se o Option for temporário. A referência precisa apontar para algo, e esse "algo" precisa viver tempo suficiente.

\n\n

Vamos ver um erro típico de iniciante:

\n\n
fn process(value: Option<String>) {\n    // Erro! cannot return reference to temporary value\n    let ref_value: Option<&str> = value.as_ref().map(|s| s.as_str());\n    // ou ainda mais direto:\n    let ref_value: Option<&str> = Some(value.unwrap().as_str()); // BUM!\n}
\n\n

O compilador explode em vermelho. Por quê? Porque value é o proprietário da string. Quando você tenta pegar um &str dela, a referência deve viver no máximo tanto quanto o próprio value. E se value for um objeto temporário (por exemplo, resultado de uma chamada de função), a referência se torna uma dangling reference.

\n\n

Solução nº 1: as_deref() — seu novo melhor amigo

\n\n

A maneira mais elegante de converter Option<String> em Option<&str> é o método as_deref().

\n\n

Como funciona? as_deref() faz duas coisas:

\n
    \n
  1. Pega um &Option<T> e o transforma em Option<&T> (isso é feito por as_ref()).
  2. \n
  3. Em seguida, aplica Deref ao valor interno, transformando &String em &str.
  4. \n
\n\n

Veja como fica no código:

\n\n
fn main() {\n    let my_string: Option<String> = Some(String::from("Olá, Rust!"));\n    \n    // Mágica em uma linha:\n    let my_str_ref: Option<&str> = my_string.as_deref();\n    \n    match my_str_ref {\n        Some(s) => println!("String: {}", s),\n        None => println!("Sem string"),\n    }\n    // my_string ainda está vivo e saudável!\n    println!("String original: {:?}", my_string);\n}
\n\n

Observe: my_string continua sendo o proprietário dos dados. Nós apenas pegamos uma referência ao seu conteúdo. Isso significa que my_str_ref só vive enquanto my_string viver.

\n\n

E se o Option estiver vazio?

\n

Simples:

\n\n
fn main() {\n    let empty: Option<String> = None;\n    let result: Option<&str> = empty.as_deref();\n    println!("{:?}", result); // None\n}
\n\n

Sem pânicos, sem crashes. Funciona como um relógio.

Blogs

Book Recommendations