当您在Rust中进行可变重影(mutably shadow)一个向量时会发生什么?

3

我目前正在学习Rustlings课程,遇到了有关移动语义的练习,感到有些困惑。以下是练习的要点:

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函数,并在函数内通过let mut vec = vec;重新定义了一个可变的同名vec变量,从而进行了可变的遮蔽操作。由于Vectors是指向堆存储的引用,这是否意味着由于遮蔽而进行了一次clone(),还是指针重复使用并只是变成了可变的?为什么在这种情况下要使用遮蔽呢?
2个回答

3

这个指针是被复用并且仅仅变成了可变的吗?

是的。实际上,在运行时,它本质上是一个无操作。

为什么在这种情况下会使用遮蔽呢?

有些人喜欢通过遮蔽的模式来暂时“锁定”和“解锁”绑定。

let a = …;
…
let mut a = a;
// mutate `a` in-place
let a = a; // lock to readonly again

那其实只是个人偏好而已。这里:

  • 可以引入一个新的变量,但它真的更有用吗?它会被称为什么? vec_mut?毕竟源头已经改变了,不太可能重新使用。
  • 或者,输入参数可以直接是mut vec: …

这主要取决于个人选择。


3

语义上,它是同一个对象,只是在您的情况下更改了名称。

但在当前实现中,它会将堆栈数据复制到堆栈中的新位置,因此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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接