在为结构实现默认特征并使用函数初始化其成员时,这些函数是计算一次还是多次?
When implementing the default trait for a struct, and intializing its members using functions, are those functions evaluated once or several times?
我在箱子里有以下伪代码
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()
会被评估多次导致打开太多连接而不是预期的一次?
好几次了。这可以简单地证明:
struct Struct;
impl Default for Struct {
fn default() -> Self {
println!("default called");
Struct
}
}
fn main() {
let s1 = Struct::default(); // prints "default called"
let s2 = Struct::default(); // prints "default called"
}
Default
特征或 default
函数没有什么特别之处。它们像任何其他特性和任何其他功能一样工作。
如果我对你的问题理解正确,你想要一个 Connection
类型的全局可变变量,你想知道每次从不同的 crate/thread 导入变量时是否会重新初始化它。
在这种情况下,您不需要默认特征。 Default
不是特殊特征。它只在标准库中,因为它很常见。要定义全局变量,您必须直接初始化值。您必须先定义类型 Connection
:
pub struct Connection {
pub id: i32,
pub speed: i32,
}
然后创建全局变量。有许多方法可以创建全局可变变量,如 this answer. Assuming that Connection
stores things other than integers you will probably need to wrap the global in an Arc
for thread-safety, and a Mutex
if you require mutability across threads. You can use lazy_static
中所述,以在运行时初始化变量,这允许您进行必要的方法调用以创建 Connection
:
lazy_static! {
pub static ref conn: Arc<Connection> = Arc::new(Connection {
id: open_connection(),
speed: get_speed_at_init(),
});
}
现在回答你的问题。
不,生成新线程或从板条箱导入变量不会重新初始化静态变量。 static
变量表示程序中的精确内存位置。所有对静态的引用都指向相同的内存位置,无论它们位于相同的模块、板条箱还是线程中。我们可以通过在 open_connection
中生成一个随机 id
并将全局 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()
}
}
您可以从多个模块或 crate 访问 conn
:
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
Playground link:不幸的是你不能在操场上有多个板条箱,所以模块是我能做的最好的。如果您仍然不确定,可以随时在本地进行测试。
我在箱子里有以下伪代码
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()
会被评估多次导致打开太多连接而不是预期的一次?
好几次了。这可以简单地证明:
struct Struct;
impl Default for Struct {
fn default() -> Self {
println!("default called");
Struct
}
}
fn main() {
let s1 = Struct::default(); // prints "default called"
let s2 = Struct::default(); // prints "default called"
}
Default
特征或 default
函数没有什么特别之处。它们像任何其他特性和任何其他功能一样工作。
如果我对你的问题理解正确,你想要一个 Connection
类型的全局可变变量,你想知道每次从不同的 crate/thread 导入变量时是否会重新初始化它。
在这种情况下,您不需要默认特征。 Default
不是特殊特征。它只在标准库中,因为它很常见。要定义全局变量,您必须直接初始化值。您必须先定义类型 Connection
:
pub struct Connection {
pub id: i32,
pub speed: i32,
}
然后创建全局变量。有许多方法可以创建全局可变变量,如 this answer. Assuming that Connection
stores things other than integers you will probably need to wrap the global in an Arc
for thread-safety, and a Mutex
if you require mutability across threads. You can use lazy_static
中所述,以在运行时初始化变量,这允许您进行必要的方法调用以创建 Connection
:
lazy_static! {
pub static ref conn: Arc<Connection> = Arc::new(Connection {
id: open_connection(),
speed: get_speed_at_init(),
});
}
现在回答你的问题。
不,生成新线程或从板条箱导入变量不会重新初始化静态变量。 static
变量表示程序中的精确内存位置。所有对静态的引用都指向相同的内存位置,无论它们位于相同的模块、板条箱还是线程中。我们可以通过在 open_connection
中生成一个随机 id
并将全局 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()
}
}
您可以从多个模块或 crate 访问 conn
:
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
Playground link:不幸的是你不能在操场上有多个板条箱,所以模块是我能做的最好的。如果您仍然不确定,可以随时在本地进行测试。