• 你理解Rust中的同名变量吗?
  • 发布于 1周前
  • 49 热度
    0 评论
在Rust中,我们可以隐藏一个变量,创建一个具有相同名称的新变量。我们看下面这个例子:
fn main() {
    let x = 5;

    let x = x + 1;

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}"); // 12
    }

    println!("The value of x is: {x}"); // 6
}
我认为原来的变量x被删除了,它的内存被释放了。但事实并非如此;该变量继续存在,并且它的内存不会被释放,即使不能通过其名称访问该值。

当使用Rc指针时,新的疑问出现了,注意到Rc指针的clone会增加ref计数器。看看这个例子:
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let ptr = Rc::as_ptr(&a);
    let a = a.clone(); // 显示一个递增计数器
    assert_eq!(Rc::strong_count(&a), 2);

    let b = a.clone();
    assert_eq!(Rc::strong_count(&a), 3);

    std::mem::drop(a); // 递减计数器
    assert_eq!(Rc::strong_count(&b), 2);

    std::mem::drop(b);
    unsafe { assert_eq!(*ptr, 5) }; // 它在堆里存活吗?
}
我们看看下面这个例子,shadowing并不等同于dropping:
struct LoudDrop(&'static str);
impl Drop for LoudDrop {
    fn drop(&mut self) {
        println!("{} dropped", self.0);
    }
}

fn main() {
    let a = LoudDrop("a1");
    let a = LoudDrop("a2");
    drop(a);
    println!("End of main");
}
这段代码的输出结果如下:
a2 dropped
End of main
a1 dropped
我们可以看到,原始的a被遮蔽了,但它在main()函数结束之前是存活的。

我们再看下面这个例子:
use std::rc::Rc;

fn main() {
    let ptr;
    {
        let a = Rc::new(5);
        ptr = Rc::as_ptr(&a);
    } //a 在这里被释放

    unsafe { assert_eq!(*ptr, 5) }; // 内存中的值仍然是5
}
当执行到代码unsafe{assert_eq!(*ptr, 5)}时,它不会检查值是否为“alive”。它检查内存中指针处的值,但不知道那个地址处的内存是否被分配了。释放内存并不会清理内存。清理内存的操作是昂贵的,所以编译器通常会避免它并留下垃圾值。”

我们再看另一个例子:
fn main() {
    let i32_ptr: *const i32;
    let f64_ptr: *const f64;
    let char_ptr: *const char;
    {
        let x: i32 = 1;
        i32_ptr = &x;
        let x = 3.14;
        f64_ptr = &x;
        let x = 'a';
        char_ptr = &x;
    }
    unsafe {
        assert_eq!(*i32_ptr, 1);
        assert_eq!(*f64_ptr, 3.14);
        assert_eq!(*char_ptr, 'a');
    }
}
在上面的例子中,所有变量都不是存活的,但是assert_eq!仍然可以工作。
用户评论