首页 > 解决方案 > 在实现结构的默认特征并使用函数初始化其成员时,这些函数是评估一次还是多次?

问题描述

我在板条箱中有以下伪代码

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()被评估多次导致打开太多连接而不是预期的一次?

标签: functionrustinitializationtraits

解决方案


如果我正确理解您的问题,您想要一个类型的全局可变变量,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

操场链接:不幸的是,操场上不能有多个板条箱,所以模块是我能做的最好的。如果您仍然不确定,您可以随时在本地进行测试。


推荐阅读