Por que você está aqui? Seja honesto
\n\nVocê 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ã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\nNeste 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\nO problema: por que não podemos simplesmente converter?
\n\nPrimeiro, 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
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.
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.
Vamos ver um erro típico de iniciante:
\n\nfn 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\nO 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.
Solução nº 1: as_deref() — seu novo melhor amigo
\n\nA maneira mais elegante de converter Option<String> em Option<&str> é o método as_deref().
Como funciona? as_deref() faz duas coisas:
- \n
- Pega um
&Option<T>e o transforma emOption<&T>(isso é feito poras_ref()). \n - Em seguida, aplica
Derefao valor interno, transformando&Stringem&str. \n
Veja como fica no código:
\n\nfn 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\nObserve: 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.
E se o Option estiver vazio?
\nSimples:
\n\nfn main() {\n let empty: Option<String> = None;\n let result: Option<&str> = empty.as_deref();\n println!("{:?}", result); // None\n}\n\nSem pânicos, sem crashes. Funciona como um relógio.