简体   繁体   English

我如何跟踪 Rust 中的结构实例?

[英]How can I track instances of structs in rust?

I have a simple example game entity called a Nation, which is a struct that contains all the data relevant to the player's assets and activities.我有一个名为国家的简单示例游戏实体,它是一个包含与玩家资产和活动相关的所有数据的结构。 The player is allowed to change their nation name, which is used to log in and take their turns.允许玩家更改他们的国家名称,用于登录和轮流。 Thus, the player has to have a unique identifier that doesn't change.因此,玩家必须有一个不会改变的唯一标识符。

There are also other things in the game system which similarly need unique identifiers, so to my dinosaur C brain, the obvious solution was to try making a global HashMap to contain the struct name as a key, and the instance count... and then auto-increment that counter whenever a new struct is created, using the current value as the ID.游戏系统中还有其他东西同样需要唯一标识符,所以对于我的恐龙 C 大脑来说,显而易见的解决方案是尝试制作一个全局 HashMap 以包含结构名称作为键,以及实例计数......然后每当创建新结构时自动增加该计数器,使用当前值作为 ID。

Rust really hates me for trying that, which is fine. Rust 真的很讨厌我尝试那样做,这很好。 But, I'd like to learn a more proper way to accomplish this.但是,我想学习一种更合适的方法来实现这一点。 Since I have to implement Default for these anyways, putting the increment and then assignment in the default() function seems like the right place to use it, but the counters themselves need to live somewhere accessible to those functions.由于无论如何我都必须为这些实现 Default,将增量和赋值放在 default() 函数中似乎是使用它的正确位置,但计数器本身需要位于这些函数可访问的地方。

Right now, I have this, which is ugly but seems to work, so far:现在,我有这个,它很丑但似乎有效,到目前为止:

static mut nation_id : i64 = 0;

#[derive(Debug)]
struct Nation {
    id          : i64,          // unique naiton ID, established at allocation
    name        : String,       // the nation name, entered at runtime
    // more stuff here...
}

impl Default for Nation {
    fn default() -> Nation {
        unsafe {
            nation_id += 1;
            Nation {
                id: nation_id,          // We want this to actually come from a counter
                name: String::from(""),
                // more stuff here...
            }
        }
    }
}

// World just holds a Vec<Nation> that is initialized to new() and thus empty.

fn main() {
    println!("This is just a test.");
    let mut w : World = Default::default();
    println!("{:?}", w);
    println!("{} nations exist.", w.nations.len());
    let mut n : Nation = Default::default();
    println!("{:?}", n);
    w.nations.push(n);
    println!("{} nations exist.", w.nations.len());
    let mut n2 : Nation = Default::default();
    println!("{:?}", n2);
    w.nations.push(n2);
    println!("{} nations exist.", w.nations.len());
    println!("Test completed.");
}

If you want a counter, one way to do that is to use atomics.如果你想要一个计数器,一种方法是使用原子。 This function will return a counter and can work on multiple threads concurrently.此函数将返回一个计数器并且可以同时在多个线程上工作。

use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering::SeqCst;

pub fn unique_id() -> u64 {
    static COUNTER: AtomicU64 = AtomicU64::new(0);
    
    COUNTER.fetch_add(1, SeqCst)
}

We can also improve it by enforcing that ids must be unique.我们还可以通过强制 ID 必须是唯一的来改进它。

pub fn unique_id() -> u64 {
    static COUNTER: AtomicU64 = AtomicU64::new(0);
    
    let id = COUNTER.fetch_add(1, SeqCst);
    assert_ne!(id, u64::MAX, "ID counter has overflowed and is no longer unique");
    id
}

Rust Playground 铁锈游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM