处理Rust中所谓的全局变量



我们都知道使用全局变量会导致一些微妙的bug。我需要将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};
static START: Once = Once::new();
static mut ARCMUT: Vec<Arc<Mutex<i32>>> = Vec::new();

//作为enum

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

相关内容

  • 没有找到相关文章

最新更新