rust - ps4 - Devuelve una cadena local como un segmento(& str)
rust traduccion (3)
Hay varias preguntas que parecen ser sobre el mismo problema que estoy teniendo.
Por ejemplo, ver
here
y
here
.
Básicamente estoy tratando de construir un
String
en una función local, pero luego lo devuelvo como
&str
.
Rebanar no funciona porque la vida útil es demasiado corta.
No puedo usar
str
directamente en la función porque necesito construirlo dinámicamente.
Sin embargo, también preferiría no devolver una
String
ya que la naturaleza del objeto en el que está entrando es estática una vez que se construye.
¿Hay alguna manera de tener mi pastel y comerlo también?
Aquí hay una reproducción mínima sin compilación:
fn return_str<''a>() -> &''a str {
let mut string = "".to_string();
for i in 0..10 {
string.push_str("ACTG");
}
&string[..]
}
En ciertos casos, se le pasa un corte de cadena y puede querer crear una nueva cadena condicionalmente.
En estos casos, puede devolver una
Cow
.
Esto permite la referencia cuando sea posible y una
String
contrario:
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()
}
}
No, no puedes hacerlo. Hay al menos dos explicaciones de por qué es así.
Primero, recuerde que las referencias son prestadas, es decir, apuntan a algunos datos pero no los poseen, es propiedad de otra persona. En este caso particular, la cadena, una porción a la que desea regresar, es propiedad de la función porque está almacenada en una variable local.
Cuando la función sale, todas sus variables locales se destruyen;
esto implica llamar a los destructores, y el destructor de
String
libera la memoria utilizada por la cadena.
Sin embargo, desea devolver una referencia prestada que apunte a los datos asignados para esa cadena.
Significa que la referencia devuelta se cuelga inmediatamente, ¡apunta a memoria no válida!
Rust fue creado, entre todo lo demás, para prevenir tales problemas. Por lo tanto, en Rust es imposible devolver una referencia apuntando a variables locales de la función, lo cual es posible en lenguajes como C.
También hay otra explicación, un poco más formal. Veamos la firma de su función:
fn return_str<''a>() -> &''a str
Recuerde que los parámetros genéricos y de por vida son, bueno, parámetros : los establece la persona que llama de la función. Por ejemplo, alguna otra función puede llamarlo así:
let s: &''static str = return_str();
Esto requiere
''a
a ser
''static
, pero por supuesto es imposible: su función no devuelve una referencia a una memoria estática, devuelve una referencia con una vida útil estrictamente menor.
Por lo tanto, dicha definición de función no es correcta y está prohibida por el compilador.
De todos modos, en tales situaciones, debe devolver un valor de un tipo propio, en este caso particular, será una
String
:
fn return_str() -> String {
let mut string = String::new();
for _ in 0..10 {
string.push_str("ACTG");
}
string
}
Puede optar por
perder memoria
para convertir una
String
en una
&''static str
:
fn return_str() -> &''static str {
let string = "ACTG".repeat(10);
Box::leak(string.into_boxed_str())
}
Esta es una muy mala idea en muchos casos, ya que el uso de memoria crecerá para siempre cada vez que se llame a esta función.
Si desea devolver la misma cadena en cada llamada, consulte también:
- Cómo crear una cadena estática en tiempo de compilación