function - 在实现结构的默认特征并使用函数初始化其成员时,这些函数是评估一次还是多次?
问题描述
我在板条箱中有以下伪代码
pub static struct connection {
pub Id: i32,
pub speed: i32,
}
impl Default for connection {
fn default() -> Self {
connection {
Id: open_connection(),
Speed: get_speed_at_init(),
}
}
}
该 crate 被导入另一个项目并运行到几个工作线程中,每个线程在无限循环中使用导入的 crate。
现在我可以使用self.connection.Id
它来执行网络操作,还是会open_connection()
被评估多次导致打开太多连接而不是预期的一次?
解决方案
如果我正确理解您的问题,您想要一个类型的全局可变变量,Connection
并且您想知道每次从不同的 crate/thread 导入变量时是否会重新初始化它。
在这种情况下,您不需要默认特征。Default
不是一个特殊的特征。它只在标准库中,因为它很常见。要定义全局变量,您必须直接初始化该值。您必须首先定义类型Connection
:
pub struct Connection {
pub id: i32,
pub speed: i32,
}
然后创建全局变量。如本答案所述,有多种方法可以创建全局可变变量。假设Connection
存储除整数以外的东西,您可能需要将全局包装在一个Arc
线程安全中,Mutex
如果您需要跨线程的可变性。您可以使用lazy_static
在运行时初始化变量,这允许您进行必要的方法调用来创建Connection
:
lazy_static! {
pub static ref conn: Arc<Connection> = Arc::new(Connection {
id: open_connection(),
speed: get_speed_at_init(),
});
}
现在回答你的问题。
不,生成新线程或从 crate 导入变量不会重新初始化静态变量。变量代表程序中的static
精确内存位置。所有对静态的引用都指向相同的内存位置,无论它们位于相同的模块、板条箱或线程中。我们可以通过生成随机id
输入open_connection
并将全局放置conn
在单独的模块中来测试这一点:
pub mod connection {
lazy_static! {
pub static ref conn: Arc<Connection> = Arc::new(Connection {
id: open_connection(),
speed: get_speed_at_init(),
});
}
fn open_connection() -> i32 {
let mut rng = rand::thread_rng();
rng.gen()
}
}
您可以conn
从多个模块或 crates 访问:
mod a {
use crate::connection::conn;
pub fn do_stuff() {
println!("id from a: {}", conn.id);
}
}
// a different crate
mod b {
use crate::connection::conn;
pub fn do_stuff() {
println!("id from b: {}", conn.id);
}
}
和多个线程:
mod c {
use crate::connection::conn;
pub fn do_stuff() {
for i in 0..5 {
std::thread::spawn(move || {
println!("id from thread #{}: {}", i, conn.id);
})
.join()
.unwrap();
}
}
}
但是id
将始终引用id
最初声明全局变量时生成的 :
fn main() {
a::do_stuff();
different_crate::b::do_stuff();
c::do_stuff();
}
// id from a: 1037769551
// id from b: 1037769551
// id from thread #0: 1037769551
// id from thread #1: 1037769551
// id from thread #2: 1037769551
// id from thread #3: 1037769551
// id from thread #4: 1037769551
操场链接:不幸的是,操场上不能有多个板条箱,所以模块是我能做的最好的。如果您仍然不确定,您可以随时在本地进行测试。
推荐阅读
- html - 在不移动其他元素的情况下增加文本栏的宽度
- hbase - Hbase rest api 多次插入
- javascript - Javascript数组计算与转换
- sqlcmd - 从 SQLCMD 输出中删除空格
- r - 将数据框转换为矩阵时保留数据框的行列顺序
- mysql - 在 SQL 中使用 SET 计算百分比时出现错误“操作数应包含 1 列”
- azure-service-fabric - 如何在服务结构集群上设置注册表项
- linux - 在 Linux 上扫描文本文件以进行质量检查(模式匹配)的最佳做法是什么?
- java - 如何创建多个数据类型的双向链表
- jpa - 是否有与杰克逊的 @JsonAnyGetter/@JsonAnySetter 等效的 JPA 注释?