107.05.05 rust 之路 04 變數

來了久等了,終於度過偏爆炸的一個禮拜 OuO
(明明就超過一個禮拜

這次主題應該偏簡單
會介紹變數 (Variable)、常數 (Constant)、Static Variable、Shadowing (遮蔽)

相對於地上的我們,天上星星的存在是接近永恆不變的
變與不變的道理....請參考前赤壁賦 (不要玩古文x
Photo by John Fowler on Unsplash


變數

不可變 (Immutable)

首先為何要提變與不變呢?
因為 Rust 中的變數預設是不可變
不可變?! 那還叫變數?
是,就它預設是這樣不然是要 @#%&

當一個變數不可變時就像是把數值綁定到一個名稱上一樣
預設不可變,主要有兩個好處:更安全、能更簡單使用 Rust 提供的並行處理 (concurrency)

實際上的不變是怎樣呢? 那就上 code 囉 OuO
首先 let 是宣告變數的關鍵字
let x = 5; // 把 5 綁定到 x 上

錯誤操作:更改不可變的變數
fn main() {
    let x = 5;
    println!("x: {}", x);
    x = 6; // 改變不可變 x --> ERROR
    println!("x: {}", x);
}

編譯器在編譯時期會報錯:
這裡會發現....Rust 的編譯器會不會太囉嗦,把所有相關錯誤的位置都列出來
因此有人說寫 Rust 其實是編譯器在教怎麼寫 OuO
error[E0384]: cannot assign twice to immutable variable `x`
 --> t.rs:4:5
  |
2 |     let x = 5;
  |         - first assignment to `x`
3 |     println!("The value of x is: {}", x);
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

那這個錯誤要怎麼改呢?
第一種解法就是不要寫 x = 6; 那行 (這不是廢話
第二種就是....

可變變數 (Mutable Variable)

是不是感覺有點奇怪,一開始就用這個就不會有問題啦!?
但是預設 (這裡指不可變) 是什麼其實很重要
因為人寫程式都傾向於使用預設,所以這樣設計時,就會不知不覺使用更安全的方式
等到預設無法滿足需求時,再去使用非預設

使用 mut
let mut x = 5; // 把 5 綁定到 x 上,且 x 為可變

這樣下面的 code 就會過了 OuO
fn main() {
    let mut x = 5;
    println!("x: {}", x);
    x = 6; // 可以改變 x 了!!!!
    println!("x: {}", x);
}

除了變數當然就還有....

常數 (Constant)

使用 const
必須宣告型別,並給初始值
不能使用 mut:常數不是預設不可變,是永遠不可變 (真●星星
只能由表達式賦值,不能是函式呼叫的結果、執行時期得到的值
整個執行時期都是有效的 (可定義在全域
命名慣例是使用全大寫英文,並使用底線連接單字

const MAX_POINTS: u32 = 100_000;

Static Variabe

大部分跟常數頗像,必須宣告型別,並給初始值,命名慣例....
但是有固定的記憶體存放此數值 (常數沒有
不過 static 可以有 mut,但是對可變的 static 變數操作時需要用 unsafe 的區塊包住
(看到 unsafe 就有點怕 w
其實要用 unsafe 是因為 static 變數是所有執行緒都可以存取的
此時變數若為可變,代表可能同時有多個執行緒改值,所以用 unsafe 警告這個區塊有危險
static N: i32 = 5;
static mut N: i32 = 5;
unsafe {
    N += 1;
    println!("N: {}", N);
}

Shadowing (遮蔽)

(不知道該不該翻成遮蔽
首先看一下這段程式碼:(註解部分是輸出的結果)
fn main() {
    let x = 5;
    println!("x: {}", x); // x: 5
    {
        let mut x = x;
        x += 1;
        println!("x: {}", x); // x: 6
    }
    println!("x: {}", x); // x: 5
}

內部區塊 (scope) 的 x 會遮蔽上一層的 x,離開區塊後不會影響外部的 x
此外也可以遮蔽同一層變數,只是被遮蔽者其數值就會被刪掉,因為沒有綁定到任何變數上
此特性有很多可以應用的地方,甚至可以轉換型別,因為是重新綁定

例如不用重新想名稱 (Hardest tasks for Programmers....)
像是官網以下面計算空白字串為例
fn main() {
    let spaces = "   ";        // 此字串只會用一次不需要儲存
    let spaces = spaces.len(); // 遮蔽,型別變成整數
    println!("{} 個空白", spaces);
}


下篇簡單說個型別

參考資料:
Variables and Mutability
const and static

沒有留言:

張貼留言

^ Top