rust - ¿Por qué es legal pedir prestado un temporal?
temporary (3)
Viniendo de C ++, estoy bastante sorprendido de que este código sea válido en Rust:
let x = &mut String::new();
x.push_str("Hello!");
En C ++, no puede tomar la dirección de un temporal, y un temporal no sobrevivirá a la expresión en la que aparece.
¿Cuánto tiempo vive el temporal en Rust?
Y dado que
x
es solo un préstamo, ¿quién es el propietario de la cadena?
¿Por qué es legal pedir prestado un temporal?
Es legal por la misma razón por la que es ilegal en C ++, porque alguien dijo que así debería ser .
¿Cuánto tiempo vive el temporal en Rust? Y dado que
x
es solo un préstamo, ¿quién es el propietario de la cadena?
La vida útil de los valores temporales es típicamente
- la declaración que encierra más íntimamente; la expresión de cola de un bloque se considera parte de la declaración que encierra el bloque, o
- la expresión de condición o la expresión condicional de bucle si el temporal se crea en la expresión de condición de un
if
o unif
/else
o en la expresión condicional deloop
de una expresión while.Sin embargo, cuando se crea un valor temporal que se asigna a una declaración
let
, el temporal se crea con la vida útil del bloque de cierre, ya que el uso de la declaración adjunta (la declaraciónlet
) sería un error garantizado (ya que un puntero a el temporal se almacenaría en una variable, pero el temporal se liberaría antes de que se pudiera usar la variable). El compilador utiliza reglas sintácticas simples para decidir qué valores se asignan a un enlace let y, por lo tanto, merecen una vida útil temporal más larga.
Esencialmente, puede tratar su código como:
let mut a_variable_you_cant_see = String::new();
let x = &mut a_variable_you_cant_see;
x.push_str("Hello!");
Ver también:
- ¿Cuál es el alcance de los valores sin nombre?
- ¿Están bien los punteros en bruto a los temporales en Rust?
De la referencia de óxido :
Vidas temporales
Cuando se usa una expresión de valor en la mayoría de los contextos de expresión de lugar, se crea una ubicación de memoria temporal sin nombre inicializada para ese valor y la expresión se evalúa en esa ubicación.
Esto aplica, porque
String::new()
es una expresión de valor y está justo debajo de
&mut
en un contexto de expresión de lugar.
Ahora el operador de referencia solo tiene que pasar por esta ubicación de memoria temporal, por lo que se convierte en el valor de todo el lado derecho (incluido el
&mut
).
Sin embargo, cuando se crea una expresión de valor temporal que se asigna a una declaración let, la temporal se crea con la vida útil del bloque que lo encierra.
Dado que está asignado a la variable, obtiene una vida útil hasta el final del bloque de cierre.
Esto también responde a esta pregunta sobre la diferencia entre
let a = &String::from("abcdefg"); // ok!
y
let a = String::from("abcdefg").as_str(); // compile error
En la segunda variante, el temporal se pasa a
as_str()
, por lo que su vida útil finaliza al final de la instrucción.
El MIR de Rust proporciona una idea de la naturaleza de los temporales; considere el siguiente caso simplificado:
fn main() {
let foo = &String::new();
}
y el MIR que produce (comentarios estándar reemplazados por los míos):
fn main() -> () {
let mut _0: ();
scope 1 {
let _1: &std::string::String; // the reference is declared
}
scope 2 {
}
let mut _2: std::string::String; // the owner is declared
bb0: {
StorageLive(_1); // the reference becomes applicable
StorageLive(_2); // the owner becomes applicable
_2 = const std::string::String::new() -> bb1; // the owner gets a value; go to basic block 1
}
bb1: {
_1 = &_2; // the reference now points to the owner
_0 = ();
StorageDead(_1); // the reference is no longer applicable
drop(_2) -> bb2; // the owner''s value is dropped; go to basic block 2
}
bb2: {
StorageDead(_2); // the owner is no longer applicable
return;
}
}
Puede ver que un propietario "invisible" recibe un valor antes de asignarle una referencia y que la referencia se descarta antes que el propietario, como se esperaba.
De lo que no estoy seguro es por qué existe un
scope 2
aparentemente inútil y por qué el propietario no se coloca dentro de ningún alcance;
Sospecho que MIR todavía no está 100% listo.