我正在编写一个系统,其中我有一个Object个集合,每个Object都有一个唯一的整数ID.下面是我在C++中的实现方法:

class Object {
public:
  Object(): id_(nextId_++) { }

private:
  int id_;
  static int nextId_;
}

int Object::nextId_ = 1;

这显然不是线程安全的,但是如果我想要的话,我可以将nextId_设为std::atomic_int,或者在nextId_++表达式周围加一个互斥体.

在Rust (最好是安全的)情况下,我该怎么做?没有静态 struct 成员,全局可变变量也不安全.我总是可以将nextId传递到new函数中,但是这些对象将被分配到多个位置,我不希望将nextId传递到任何地方.思想?

推荐答案

全局可变变量也不安全

你的C++例子看起来好像有线程安全问题,但是我不知道足够的C++来确定.

然而,只有unsynchronized个全局可变变量存在问题.如果不关心跨线程问题,可以使用本地线程:

use std::cell::Cell;

#[derive(Debug)]
struct Monster {
    id: usize,
    health: u8,
}

thread_local!(static MONSTER_ID: Cell<usize> = Cell::new(0));

impl Monster {
    fn new(health: u8) -> Monster {
        MONSTER_ID.with(|thread_id| {
            let id = thread_id.get();
            thread_id.set(id + 1);
            Monster { id, health }
        })
    }
}

fn main() {
    let gnome = Monster::new(41);
    let troll = Monster::new(42);

    println!("gnome {:?}", gnome);
    println!("troll {:?}", troll);
}

如果你确实想让多线程更好地工作,请查看bluss' answer,它展示了如何使用原子变量.

Rust相关问答推荐

如何从接收&;self的方法克隆RC

如何在Rust中实现Functor trait?

当两者都有效时,为什么Rust编译器建议添加';&;而不是';*';?

返回的future 不是`发送`

带扫描的铁 rust 使用滤镜

修改切片/引用数组

为什么std repeat trait绑定在impl块和关联函数之间?

关于如何初始化弱 struct 字段的语法问题

带参考文献的 rust 元组解构

为什么';t std::cell::ref使用引用而不是非空?

减少指示ProgressBar在Rust中的开销

如何在 `connect_activate()` 之外创建一个 `glib::MainContext::channel()` 并将其传入?

Rust 重写函数参数

如何限制 GtkColumnView 行数

为什么需要同时为值和引用实现`From`?方法不应该自动解引用或borrow 吗?(2023-06-16)

如何将 Rust 字符串转换为 i8(c_char) 数组?

RAII 模式的 Rust 解决方案,用于在 new() 和 drop() 上修改另一个对象

相交着色器从 SSBO 中读取零

类型组的通用枚举

在 Rust 中组合特征的不同方法是否等效?