在 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());
}

Playground

如果您更喜欢使用闭包,您也可以这样做,但您需要使用内部可变性来允许多个闭包捕获相同的环境。例如,您可以使用 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());
}

Playground

无依赖性示例 enumfunction。编辑:根据评论中的建议改进了代码并更正了匹配臂。

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

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

static mut ARCMUT: Vec<Arc<Mutex<i32>>> = Vec::new();

// 作为枚举

enum Operation {
    Add,
    Subtract,
}

impl Operation {
    // static change

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


    // dynamic change

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

// 作为函数

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

//作为特征

trait OperationTrait {
    fn add(self) -> Self;
    fn subtract(self) -> Self;
    fn return_value(self) ->i32;
}

impl OperationTrait for i32 {
    fn add(mut self) -> Self {
        let arc_clone = unsafe{ARCMUT[0].clone()};
        let mut unlock = arc_clone.lock().unwrap();
        *unlock += self;
        self
    }

    fn subtract(mut self) -> Self {
        let arc_clone = unsafe{ARCMUT[0].clone()};
        let mut unlock = arc_clone.lock().unwrap();
        *unlock -= self;
        self
    }

    fn return_value(self)->Self{
        let arc_clone = unsafe{ARCMUT[0].clone()};
        let mut unlock = arc_clone.lock().unwrap();
        *unlock
    }

}

// fn main

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

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

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

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

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

    let test = add();

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

    let test = 4000.add();

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

}