簡體   English   中英

在 Rust 中處理所謂的全局變量

[英]Dealing with so-called global variables in Rust

我們都知道使用全局變量會導致細微的錯誤。 我需要將 Python 程序遷移到 Rust,盡可能保持算法完整。 一旦我證明了 Python-Rust 的等效性,就會有機會調試和更改邏輯以更好地適應 Rust。 這是一個使用全局變量的簡單 Python 程序,后面是我失敗的 Rust 版本。

# global variable 
a = 15

# function to perform addition 
def add(): 
    global a
    a += 100

# function to perform subtraction
def subtract(): 
    global a
    a -= 100

# Using a global through functions
print("Initial value of a  = ", a)
add() 
print("a after addition   = ", a)
subtract() 
print("a after subtraction = ", a)

這是一個運行的 Rust 程序,但我無法通過閉包來更新所謂的全局變量。

fn fmain() {
// global variable 
    let mut a = 15;

// perform addition 
    let add = || {
        let mut _name = a;
//        name += 100;  // the program won't compile if this is uncommented
    };

    call_once(add);

//  perform subtraction
    let subtract = || {
        let mut _name = a;
//        name -= 100;  // the program won't compile if this is uncommented
    };

    call_once(subtract);

    // Using a global through functions
    println!("Initial value of a    = {}", a);
    add();
    println!("a after addition      = {}", a);
    subtract();
    println!("a after subtraction   = {}", a);
}

fn main() {
    fmain();   
}

fn call_once<F>(f: F)
where
    F: FnOnce(),
{
    f();
}

我的要求:在 Rust 中重新創建 Python 邏輯。

您的 Rust 代碼沒有使用全局變量, a變量是堆棧分配的。 雖然 Rust 並不特別支持全局變量,但您當然可以使用它們。 轉換為使用實際全局變量的 Rust,您的程序將如下所示:

use lazy_static::lazy_static;
use parking_lot::Mutex; // or std::sync::Mutex

// global variable
lazy_static! {
    static ref A: Mutex<u32> = Mutex::new(15);
}

// function to perform addition
fn add() {
    *A.lock() += 100;
}

// function to perform subtraction
fn subtract() {
    *A.lock() -= 100;
}

fn main() {
    // Using a global through functions
    println!("Initial value of a  = {}", A.lock());
    add();
    println!("a after addition    = {}", A.lock());
    subtract();
    println!("a after subtraction = {}", A.lock());
}

操場

如果您更喜歡使用閉包,您也可以這樣做,但是您需要使用內部可變性來允許多個閉包捕獲相同的環境。 例如,您可以使用Cell

use std::cell::Cell;

fn main() {
    let a = Cell::new(15);
    let add = || {
        a.set(a.get() + 100);
    };
    let subtract = || {
        a.set(a.get() - 100);
    };

    // Using a global through functions
    println!("Initial value of a    = {}", a.get());
    add();
    println!("a after addition      = {}", a.get());
    subtract();
    println!("a after subtraction   = {}", a.get());
}

操場

無依賴示例,如enumfunction 編輯:代碼改進,如評論和更正匹配臂中的建議。

use std::sync::{Arc, Mutex, Once};

#[derive(Debug, Clone)]
struct ArcMut<T> {
    value: Vec<T>,
}

static START: Once = Once::new();

static mut ARCMUT: ArcMut<Arc<Mutex<u32>>> = ArcMut { value: Vec::new() };

// 作為枚舉

enum Operation {
    Add,
    Subtract,
}

impl Operation {

// 靜態變化

    fn result(self) -> u32 {
        let mut arc_clone = unsafe { ARCMUT.value[0].clone() };
        let mut unlock = arc_clone.lock().unwrap();
        match self {
            Operation::Add => *unlock += 100,
            Operation::Subtract => *unlock -= 100,
        }
        *unlock
    }

    

// 動態變化

    fn ammount(self, amount: u32) -> u32 {
        let mut arc_clone = unsafe { ARCMUT.value[0].clone() };
        let mut unlock = arc_clone.lock().unwrap();
        match self {
            Operation::Add => *unlock += amount,
            Operation::Subtract => *unlock -= amount,
        }
        *unlock
    }
}

// 作為函數

fn add() -> u32 {
    let mut arc_clone = unsafe { ARCMUT.value[0].clone() };
    let mut unlcok = arc_clone.lock().unwrap();
    *unlcok += 100;
    *unlcok
}

fn main() {
    START.call_once(|| unsafe {
        ARCMUT = ArcMut {
            value: vec![Arc::new(Mutex::new(15))],
        }
    });

    let test = Operation::Add.result();

    println!("{:?}", test);

    let test = Operation::Subtract.ammount(100);

    println!("{:?}", test);

    let test = add();

    println!("{:?}", test);
}

暫無
暫無

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

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