Retornar String local como uma fatia (& str)

Existem várias perguntas que parecem ser sobre o mesmo problema que estou tendo. Por exemplo, veja aqui e aqui . Basicamente eu estou tentando construir um String em uma function local, mas depois retorná-lo como um &str . O fatiamento não está funcionando porque o tempo de vida é muito curto. Eu não posso usar str diretamente na function porque eu preciso construí-lo dinamicamente. No entanto, eu também prefiro não retornar um String já que a natureza do object em que ele está entrando é estática, uma vez que ele é construído. Existe uma maneira de ter meu bolo e comê-lo também?

Aqui está uma reprodução mínima não-compilada:

 fn return_str() -> &'a str { let mut string = "".to_string(); for i in 0..10 { string.push_str("ACTG"); } &string[..] } 

Não, você não pode fazer isso. Há pelo menos duas explicações porque é assim.

Primeiro, lembre-se de que as referências são emprestadas, isto é, elas apontam para alguns dados, mas não são de propriedade deles, são de propriedade de outra pessoa. Nesse caso específico, a string, uma fatia para a qual você deseja retornar, pertence à function porque ela é armazenada em uma variável local.

Quando a function sai, todas as suas variables ​​locais são destruídas; isso envolve a chamada de destruidores e o destruidor de String libera a memory usada pela string. No entanto, você deseja retornar uma referência emprestada apontando para os dados alocados para essa sequência. Isso significa que a referência retornada imediatamente fica pendente – aponta para memory inválida!

Rust foi criado, entre outras coisas, para evitar tais problemas. Portanto, em Rust é impossível retornar uma referência apontando para variables ​​locais da function, o que é possível em linguagens como C.

Há também outra explicação, um pouco mais formal. Vamos ver sua assinatura de function:

 fn return_str< 'a>() -> &'a str 

Lembre-se que os parâmetros genéricos e vitalícios são, bem, parâmetros : eles são definidos pelo chamador da function. Por exemplo, alguma outra function pode chamá-lo assim:

 let s: &'static str = return_str(); 

Isto requer 'a a ser 'static , mas é obviamente impossível – sua function não retorna uma referência a uma memory estática, ela retorna uma referência com uma vida estritamente menor. Assim, essa definição de function é insegura e é proibida pelo compilador.

De qualquer forma, em tais situações você precisa retornar um valor de um tipo de propriedade, neste caso em particular, será uma String propriedade:

 fn return_str() -> String { let mut string = String::new(); for _ in 0..10 { string.push_str("ACTG"); } string } 

Em certos casos, você recebe uma fatia de string e pode querer criar uma nova string. Nestes casos, você pode devolver uma Cow . Isso permite a referência quando possível e uma String caso contrário:

 use std::borrow::Cow; fn return_str< 'a>(name: &'a str) -> Cow< 'a, str> { if name.is_empty() { let name = "ACTG".repeat(10); name.into() } else { name.into() } } 

Você pode escolher vazar memory para converter uma String uma String &'static str :

 fn return_str() -> &'static str { let string = "ACTG".repeat(10); Box::leak(string.into_boxed_str()) } 

Esta é uma idéia muito ruim em muitos casos, pois o uso da memory aumentará para sempre toda vez que essa function for chamada.

Se você quisesse retornar a mesma string a cada chamada, veja também:

  • Como criar uma string estática em tempo de compilation