La risposta di @ m-n mi ha impostato sulla strada giusta. Si tratta di indirizzi stack! Ecco una dimostrazione che ha solidificato nella mia mente cosa sta realmente accadendo.
struct Point {
x: i64,
y: i64,
}
fn main() {
{
println!("== clobber binding");
let a = 1;
println!("val={} | addr={:p}", a, &a);
// This is completely new variable, with a different stack address
let a = 2;
println!("val={} | addr={:p}", a, &a);
}
{
println!("== reassign");
let mut b = 1;
println!("val={} | addr={:p}", b, &b);
// uses same stack address
b = 2;
println!("val={} | addr={:p}", b, &b);
}
{
println!("== Struct: clobber binding");
let p1 = Point{ x: 1, y: 2 };
println!(
"xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}",
p1.x, p1.y, &p1, &p1.x, &p1.y);
let p1 = Point{ x: 3, y: 4 };
println!(
"xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}",
p1.x, p1.y, &p1, &p1.x, &p1.y);
}
{
println!("== Struct: reassign");
let mut p1 = Point{ x: 1, y: 2 };
println!(
"xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}",
p1.x, p1.y, &p1, &p1.x, &p1.y);
// each of these use the same addresses; no new addresses
println!(" (entire struct)");
p1 = Point{ x: 3, y: 4 };
println!(
"xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}",
p1.x, p1.y, &p1, &p1.x, &p1.y);
println!(" (individual members)");
p1.x = 5; p1.y = 6;
println!(
"xval,yval=({}, {}) | pointaddr={:p}, xaddr={:p}, yaddr={:p}",
p1.x, p1.y, &p1, &p1.x, &p1.y);
}
}
uscita (gli indirizzi sono ovviamente un po 'diverso per ogni corsa):
== clobber binding
val=1 | addr=0x7fff6112863c
val=2 | addr=0x7fff6112858c
== reassign
val=1 | addr=0x7fff6112847c
val=2 | addr=0x7fff6112847c
== Struct: clobber binding
xval,yval=(1, 2) | pointaddr=0x7fff611282b8, xaddr=0x7fff611282b8, yaddr=0x7fff611282c0
xval,yval=(3, 4) | pointaddr=0x7fff61128178, xaddr=0x7fff61128178, yaddr=0x7fff61128180
== Struct: reassign
xval,yval=(1, 2) | pointaddr=0x7fff61127fd8, xaddr=0x7fff61127fd8, yaddr=0x7fff61127fe0
(entire struct)
xval,yval=(3, 4) | pointaddr=0x7fff61127fd8, xaddr=0x7fff61127fd8, yaddr=0x7fff61127fe0
(individual members)
xval,yval=(5, 6) | pointaddr=0x7fff61127fd8, xaddr=0x7fff61127fd8, yaddr=0x7fff61127fe0
I punti chiave sono questi:
- Usa
let
a "clobber" un (nuovo indirizzo esistente vincolante pila). Ciò accade anche se la variabile è stata dichiarata mut
, quindi fai attenzione.
- Utilizzare
mut
per riutilizzare l'indirizzo stack esistente, ma non utilizzare let
durante la riassegnazione.
Questo test rivela un paio di cose interessanti:
- Se si riassegna un intero struct mutabile, è equivalente ad assegnare ogni membro singolarmente.
- L'indirizzo della variabile che contiene la struct è uguale all'indirizzo del primo membro. Immagino che questo abbia senso se provieni da uno sfondo C/C++.
Mi hai impostato sulla strada giusta Avevo bisogno di scrivere una demo per vederlo in azione (vedi la mia risposta) – Kelvin
@ Kelvin Grazie per aver postato la tua demo. È un bel modo di metterlo. –