当你在 Rust 中可变地隐藏一个 Vector 时会发生什么?
What happens when you mutably shadow a Vector in Rust?
我目前正在学习 rustlings 课程,当这个关于 move-semantics 的练习出现时,我感到很困惑。这是它的要点:
fn main(){
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
//stuff happens
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec;
//do stuff
vec
}
据我所知,不可变 vec0
正在作为参数 vec
移至 fill_vec
,然后可变 shadowed let mut vec = vec;
。由于 Vectors 是对堆存储的引用,这是否意味着 clone()
由于阴影而发生,或者是否重复使用了相同的指针并使其可变?为什么要在这种情况下使用阴影?
is the same pointer reused and just made mutable?
是的。完全相同的对象,在运行时它本质上是一个空操作。
Why would shadowing be used in this case at all?
有些人喜欢通过阴影暂时“锁定”和“解锁”绑定的模式,例如
let a = …;
…
let mut a = a;
// mutate `a` in-place
let a = a; // lock to readonly again
这真的只是个人喜好。这里:
- 本可以引入一个新变量,但它真的会更有用吗?它会叫什么?
vec_mut
?不像源可以重复使用,它被移动了。
- 或者,输入参数可以直接
mut vec: …
。
这主要取决于个人选择。
从语义上讲,它是同一个对象,只是在您的情况下更改了名称。
但在当前的实现中,它会将您的堆栈数据复制到堆栈中的新位置,因此 Vec 对象的地址将发生变化(但堆指针保持不变)。
这是这样做的,因为你可以用新对象隐藏旧名称:
let v = make_first_vec();
let mut v = make_second_vec();
// old v still exists and it would be dropped only at end of block.
更好的例子(你可以运行):
struct Droppable(i32);
impl Drop for Droppable{
fn drop(&mut self){
println!("Dropping {}", self.0);
}
}
fn main(){
// Same object moved
// Changes stack location but still same object
// dropped only once
println!("Same object moved begin");
{
let a = Droppable(1);
let old_ref = &a;
println!("Address is {}", &a as *const _ as usize);
let mut a = a;
println!("Address is {}", &a as *const _ as usize);
let a = a;
println!("Address is {}", &a as *const _ as usize);
// Cannot use old reference because old object is moved
// Compile error if uncommented
// println!("Old object is still alive and has {}", old_ref.0);
}
println!("Same object moved end");
// Different object hides
// dropped in reverse order
println!("Different object hides begin");
{
let a = Droppable(2);
let old_ref = &a;
println!("Address is {}", &a as *const _ as usize);
let a = Droppable(3);
println!("Address is {}", &a as *const _ as usize);
println!("Old object is still alive and has {}", old_ref.0);
}
println!("Different object hides end");
// Different object overrides
// old object dropped when overrided
println!("Different object override begin");
{
let mut a = Droppable(4);
let old_ref = &a;
println!("Address is {}", &a as *const _ as usize);
a = Droppable(5);
println!("Address is same {}", &a as *const _ as usize);
// Cannot use old reference because old object destroyed
// Compile error if uncommented
// println!("Old object is still alive and has {}", old_ref.0);
}
println!("Different object override end");
}
它打印这个:
Same object moved begin
Address is 140736088967924
Address is 140736088967888
Address is 140736088967892
Dropping 1
Same object moved end
Different object hides begin
Address is 140736088967888
Address is 140736088967892
Old object is still alive and has 2
Dropping 3
Dropping 2
Different object hides end
Different object override begin
Address is 140736088967892
Dropping 4
Address is same 140736088967892
Dropping 5
Different object override end
我目前正在学习 rustlings 课程,当这个关于 move-semantics 的练习出现时,我感到很困惑。这是它的要点:
fn main(){
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
//stuff happens
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec;
//do stuff
vec
}
据我所知,不可变 vec0
正在作为参数 vec
移至 fill_vec
,然后可变 shadowed let mut vec = vec;
。由于 Vectors 是对堆存储的引用,这是否意味着 clone()
由于阴影而发生,或者是否重复使用了相同的指针并使其可变?为什么要在这种情况下使用阴影?
is the same pointer reused and just made mutable?
是的。完全相同的对象,在运行时它本质上是一个空操作。
Why would shadowing be used in this case at all?
有些人喜欢通过阴影暂时“锁定”和“解锁”绑定的模式,例如
let a = …;
…
let mut a = a;
// mutate `a` in-place
let a = a; // lock to readonly again
这真的只是个人喜好。这里:
- 本可以引入一个新变量,但它真的会更有用吗?它会叫什么?
vec_mut
?不像源可以重复使用,它被移动了。 - 或者,输入参数可以直接
mut vec: …
。
这主要取决于个人选择。
从语义上讲,它是同一个对象,只是在您的情况下更改了名称。
但在当前的实现中,它会将您的堆栈数据复制到堆栈中的新位置,因此 Vec 对象的地址将发生变化(但堆指针保持不变)。 这是这样做的,因为你可以用新对象隐藏旧名称:
let v = make_first_vec();
let mut v = make_second_vec();
// old v still exists and it would be dropped only at end of block.
更好的例子(你可以运行):
struct Droppable(i32);
impl Drop for Droppable{
fn drop(&mut self){
println!("Dropping {}", self.0);
}
}
fn main(){
// Same object moved
// Changes stack location but still same object
// dropped only once
println!("Same object moved begin");
{
let a = Droppable(1);
let old_ref = &a;
println!("Address is {}", &a as *const _ as usize);
let mut a = a;
println!("Address is {}", &a as *const _ as usize);
let a = a;
println!("Address is {}", &a as *const _ as usize);
// Cannot use old reference because old object is moved
// Compile error if uncommented
// println!("Old object is still alive and has {}", old_ref.0);
}
println!("Same object moved end");
// Different object hides
// dropped in reverse order
println!("Different object hides begin");
{
let a = Droppable(2);
let old_ref = &a;
println!("Address is {}", &a as *const _ as usize);
let a = Droppable(3);
println!("Address is {}", &a as *const _ as usize);
println!("Old object is still alive and has {}", old_ref.0);
}
println!("Different object hides end");
// Different object overrides
// old object dropped when overrided
println!("Different object override begin");
{
let mut a = Droppable(4);
let old_ref = &a;
println!("Address is {}", &a as *const _ as usize);
a = Droppable(5);
println!("Address is same {}", &a as *const _ as usize);
// Cannot use old reference because old object destroyed
// Compile error if uncommented
// println!("Old object is still alive and has {}", old_ref.0);
}
println!("Different object override end");
}
它打印这个:
Same object moved begin
Address is 140736088967924
Address is 140736088967888
Address is 140736088967892
Dropping 1
Same object moved end
Different object hides begin
Address is 140736088967888
Address is 140736088967892
Old object is still alive and has 2
Dropping 3
Dropping 2
Different object hides end
Different object override begin
Address is 140736088967892
Dropping 4
Address is same 140736088967892
Dropping 5
Different object override end