簡體   English   中英

Rust中相同作用域中的可變陰影?

[英]Variable shadowing in the same scope in Rust?

fn main() {
    let x = 5;
    println!("{}", x);

    let x = 3.14;
    println!("{}", x);

    let x = "Hello";
    println!("{}", x);
}
  1. 以前的值會怎樣? 我的理解是它們沒有被摧毀。

  2. 有沒有辦法訪問這些值?

  3. 如果它們仍在消耗內存空間,是否可以釋放該空間?

  1. 以前的值會怎樣?

沒有。

  1. 有沒有辦法訪問這些值?

沒有。

  1. 如果它們仍在消耗內存空間,是否可以釋放該空間?

沒有。


現在,從代碼的角度來看,以上所有內容都應該是正確的。 優化器的角度來看,它們不一定是正確的。 例如,優化器可能會注意到第一個x和第二個x的用法不重疊,因此它可以將第一個x的堆棧存儲重用於第二個x

否則可能不會。 就我所知,語言本身對此主題沒有意見。

我知道,可以保證局部變量一定釋放其堆棧存儲的唯一方法是從其定義的函數中返回。

...好吧,直到您考慮內聯 ,這也可能使之不成立。

簡短版:不用擔心,除非您使用了太多的堆棧空間,否則會引起實際的,可測量的問題。

該值可以在變量被屏蔽之前移出,但最終無法從陰影變量訪問該值。

問題1的答案: 決定取決於編譯器 ,數據類型和大小以及操作系統和系統內存負載(通常,基於堆棧的數據類型停留在main的末尾,如果占用空間大,基於堆的數據類型可能需要刪除)需要)。
問題2的答案:陰影之后: ,陰影之前:是( ),運行此代碼
問題3的答案:陰影之后: ,陰影之前:請參閱: 處置一個值 Rust手動內存管理


可變范圍和陰影:
好處:
1.由於無法從外部范圍訪問數據,因此保留了數據完整性。
2.當“我們需要更多字母”時,這是限制變量范圍的好方法。 當您需要更多局部變量或范圍時,此方法也很好用。


在遮蔽之前仍可訪問這些值的一種方法(注意:move強制閉包獲得'x'的所有權):

use std::{thread, time};
fn main() {
    let mut v = vec![];
    let d = time::Duration::from_millis(100);

    let x = 5;
    println!("{}", x);
    v.push(thread::spawn(move || {
        for _ in 1..10 {
            thread::sleep(d);
            println!("Thread 1: {}", x);
        }
    }));

    let x = 3.14;
    println!("{}", x);
    v.push(thread::spawn(move || {
        for _ in 1..10 {
            thread::sleep(d);
            println!("Thread 2: {}", x);
        }
    }));

    let x = "Hello";
    println!("{}", x);
    v.push(thread::spawn(move || {
        for _ in 1..10 {
            thread::sleep(d);
            println!("Thread 3: {}", x);
        }
    }));

    for child in v {
        let _ = child.join();
    }
}

輸出:

5
3.14
Hello
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 2: 3.14
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 1: 5
Thread 3: Hello
Thread 3: Hello
Thread 2: 3.14
Thread 1: 5
Thread 1: 5
Thread 2: 3.14
Thread 3: Hello

注意: move強制閉包獲得'x'的所有權,因此本地x的地址與線程x是:

use std::thread;
fn main() {
    let mut v = vec![];

    let x = 5;
    println!("{:p}", &x);
    v.push(thread::spawn(move || {
        println!("Thread 1: {:p}", &x);
    }));

    let x = 3.14;
    println!("{:p}", &x);
    v.push(thread::spawn(move || {
        println!("Thread 2: {:p}", &x);
    }));

    let x = "Hello";
    println!("{:p}", &x);
    v.push(thread::spawn(move || {
        println!("Thread 3: {:p}", &x);
    }));

    for child in v {
        let _ = child.join();
    }
}

輸出:

0x8bf934
0x8bf9b8
0x8bfa40
Thread 1: 0x4a3faec
Thread 2: 0x4c3fae8
Thread 3: 0x4e3fa70

據我所知,關於陰影,只有一件事要牢記:當值被堆分配時。

書中

請注意,為名稱加上陰影不會改變或破壞它所綁定的值,並且該值將繼續存在,直到超出范圍為止,即使它無法以任何方式訪問

上一個值在陰影化之后不再可訪問,並且它將在作用域末尾而不是在變量被陰影化時銷毀。

如果值在堆棧上,則無需擔心:堆棧內存管理完全在處理器手中。

相反,如果該值是堆分配的,則影子可以看作是臨時內存泄漏,它將在作用域末尾釋放。

如果這可能是一個問題,我們可以在陰影之前使用drop()顯式釋放內存:

struct Foo {
    _v: Vec<i32>
}

impl Drop for Foo {
    fn drop(&mut self) {
        println!("dropping foo");
    }
}


fn main() {
    println!("start");

    let x = Foo {_v: vec![1,2,3]};

    drop(x);

    let x = 100;

    println!("end");

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM