Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如何创建一个全局的、可变的单例?_Rust - Fatal编程技术网

Rust 如何创建一个全局的、可变的单例?

Rust 如何创建一个全局的、可变的单例?,rust,Rust,创建和使用系统中只有一个实例化的结构的最佳方法是什么?是的,这是必要的,它是OpenGL子系统,制作多个副本并到处传递会增加混乱,而不是减轻混乱 单身汉需要尽可能的高效。似乎不可能在静态区域存储任意对象,因为它包含一个带有析构函数的Vec。第二个选项是在静态区域存储一个(不安全的)指针,指向堆分配的单例。在保持语法简洁的同时,最方便、最安全的方法是什么 一般避免全局状态。相反,在早期的某个地方构造对象(可能在main中),然后将对该对象的可变引用传递到需要它的地方。这通常会使您的代码更容易推理,

创建和使用系统中只有一个实例化的结构的最佳方法是什么?是的,这是必要的,它是OpenGL子系统,制作多个副本并到处传递会增加混乱,而不是减轻混乱

单身汉需要尽可能的高效。似乎不可能在静态区域存储任意对象,因为它包含一个带有析构函数的
Vec
。第二个选项是在静态区域存储一个(不安全的)指针,指向堆分配的单例。在保持语法简洁的同时,最方便、最安全的方法是什么 一般避免全局状态。相反,在早期的某个地方构造对象(可能在
main
中),然后将对该对象的可变引用传递到需要它的地方。这通常会使您的代码更容易推理,并且不需要太多的向后弯曲

在决定是否需要全局可变变量之前,仔细看看镜子中的自己。很少有情况下它是有用的,所以这就是为什么它值得知道如何做

还想做一个

提示 在以下3种解决方案中:

  • 如果您删除了,那么您就有了一个没有任何可变性的全局单例
  • 您还可以使用而不是
    互斥体
    允许多个并发读卡器
使用
lazy static
这个板条箱可以省去手工创建一个单件的一些繁琐工作。这是一个全局可变向量:

使用lazy\u static::lazy\u static;//1.4.0
使用std::sync::Mutex;
懒惰的人!{
静态引用数组:Mutex=Mutex::new(vec![]);
}
fn do_a_call(){
ARRAY.lock().unwrap().push(1);
}
fn main(){
do___call();
do___call();
do___call();
println!(“调用{}”,ARRAY.lock().unwrap().len());
}
使用
一次\u单元
这个板条箱可以省去手工创建一个单件的一些繁琐工作。这是一个全局可变向量:

use once_cell::sync::Lazy;//1.3.1
使用std::sync::Mutex;
静态数组:Lazy=Lazy::new(| | Mutex::new(vec![]);
fn do_a_call(){
ARRAY.lock().unwrap().push(1);
}
fn main(){
do___call();
do___call();
do___call();
println!(“调用{}”,ARRAY.lock().unwrap().len());
}
使用
std::sync::SyncLazy
标准库正在添加once\u cell
的功能,当前称为:

#![功能(一次电池)]//1.53.0-每晚(2021-04-01 d474075a8f28ae9a410e)
使用std::{lazy::SyncLazy,sync::Mutex};
静态数组:SyncLazy=SyncLazy::new(| | Mutex::new(vec![]);
fn do_a_call(){
ARRAY.lock().unwrap().push(1);
}
fn main(){
do___call();
do___call();
do___call();
println!(“调用{}”,ARRAY.lock().unwrap().len());
}
特例:原子学 如果只需要跟踪整数值,可以直接使用:

使用std::sync::atomic::{AtomicUsize,Ordering};
静态调用计数:AtomicUsize=AtomicUsize::new(0);
fn do_a_call(){
CALL_COUNT.fetch_add(1,Ordering::SeqCst);
}
fn main(){
do___call();
do___call();
do___call();
println!(“调用{}”,CALL_COUNT.load(Ordering::SeqCst));
}
手动、无依赖性的实现 这是很大的抄袭与一些调整现代生锈。您还应该看看的现代实现。我已经对每一行的功能进行了内联注释

使用std::sync::{Arc,Mutex,Once};
使用std::time::Duration;
使用std::{mem,thread};
#[衍生(克隆)]
结构单音阅读器{
//因为我们将在许多线程中使用,所以我们需要保护
//并发访问
内部:弧形,
}
fn singleton()->SingletonReader{
//将其初始化为空值
静态mut SINGLETON:*常量SingletonReader=0作为*const SingletonReader;
静态一次:一次=一次::新建();
不安全{
一次。给你打一次电话{
//成功
设singleton=SingletonReader{
内部:Arc::new(互斥体::new(0)),
};
//把它放在堆中,这样它就可以比这个调用更长寿
SINGLETON=mem::transmute(Box::new(SINGLETON));
});
//现在,我们提供了一个可以安全地同时使用的数据副本。
(*SINGLETON.clone()
}
}
fn main(){
//让我们在几个线程中使用singleton
let线程:Vec=(0..10)
.map(|i|{
线程::生成(移动| |{
线程::睡眠(持续时间::从_毫秒(i*10));
设s=singleton();
让mut data=s.inner.lock().unwrap();
*数据=i为u8;
})
})
.收集();
//让我们经常检查一下单身汉
对于0u8..20中的uu{
线程::睡眠(持续时间::从_毫秒(5));
设s=singleton();
让data=s.inner.lock().unwrap();
println!(“它是:{},*数据);
}
用于threads in threads.into_iter()中的线程{
thread.join().unwrap();
}
}
这将打印出:

它是:0
它是:1
它是:1
它是:2
它是:2
它是:3
它是:3
它是:4
它是:4
它是:5
它是:5
它是:6
它是:6
它是:7
它是:7
它是:8
它是:8
是:9点
是:9点
是:9点
此代码使用Rust 1.42.0编译。
Stdin
的实际实现使用一些不稳定的特性来尝试释放分配的内存,而这段代码没有

实际上,您可能希望实现
SingletonReader
,这样您就不必亲自插入对象并锁定它

所有这些工作都是lazy static或once_cell为您所做的

“全球”的含义 请注意,您仍然可以使用普通的Rust作用域和模块级隐私来控制对
static
lazy\u static
变量的访问。这意味着您可以在模块中甚至在函数内部声明它,然后
use std::sync::{Arc, RwLock};

#[derive(Default)]
struct Config {
    pub debug_mode: bool,
}

impl Config {
    pub fn current() -> Arc<Config> {
        CURRENT_CONFIG.with(|c| c.read().unwrap().clone())
    }
    pub fn make_current(self) {
        CURRENT_CONFIG.with(|c| *c.write().unwrap() = Arc::new(self))
    }
}

thread_local! {
    static CURRENT_CONFIG: RwLock<Arc<Config>> = RwLock::new(Default::default());
}

fn main() {
    Config { debug_mode: true }.make_current();
    if Config::current().debug_mode {
        // do something
    }
}