Idiomatic rust way to generate unique id

Consider this code which guarantees (up to i64 overflow) unique ids:

pub struct IDManager {
  next_id: Cell<i64>

impl IDManager {
  pub fn new() -> IDManager {
    IDManager { next_id: Cell::new(1) }

  pub fn get_id(&self) -> i64 {
    let ans = self.next_id.get();
    self.next_id.set(ans + 1);

Now, I want a singleton IDManager which is to be used in lots of functions.

Is the idiomatic Rust way to do this:

  1. create a IDManager in main, and pass it around

  2. create a global via lazy_static

I'm using this in rust/wasm32, so concurrency is not a issue.

I'd use a global atomic integer and not use lazy_static. You don't need the atomicity in wasm, but it doesn't hurt you either, and avoiding lazy_static gives you some (insignificant) performance back. Plus for free your code works with threads.

See e.g. the thread counting example in



static COUNTER = AtomicUsize::new(1);
fn get_id() -> usize { COUNTER.fetch_add(1, Ordering::Relaxed) }

This is the exact kind of things atomics are for.


@droundy : On a related note, I was not aware of the overhead of lazy_static. Is there any overhead besides the initialization ?

@CAD97: Thanks for sample code -- I'm (pleasantly) surprised by the simplicity of the solution.

Another nice touch: you can put the static inside the function to make sure nobody can mess with it:

use std::sync::atomic::{AtomicUsize, Ordering};
fn get_id() -> usize {
    static COUNTER:AtomicUsize = AtomicUsize::new(1);
    COUNTER.fetch_add(1, Ordering::Relaxed)

At least an atomic load on every access, so nothing to worry about in the vast majority of cases (esp. with a branch predictor)

1 Like

@scottmcm :

static inside function

is really cool -- and for whatever reason, I did not realize this was possible until now

Future tip: Rust is a very uniform language. Wherever you can put an item, there's a good chance you can put any other item there, too. You can put functions inside functions, modules inside functions, heck, even modules inside a block that is the initializer expression of a static – playground.

This is not a coincidence: it makes writing code much easier, implementation details more elegant to hide, and a lot of useful macro-based tricks possible at all.


It requires checking on every dereference whether it had been initialized. It's essentially like the C pattern of setting a pointer to null and then on every use checking if it's null and initialized it if that is the case.

1 Like

does this move the initialization to first-call time, as this would do in C++? (i'd venture guess not, because if so it's essentially the same as lazy_static)

A static has no initialization code to run. This is why you can only assign it constants or outputs from a const fn, because otherwise it is not able to hard code the initial value in the binary.

Rust does typically not have code that runs before main.


No. In rust, where you put an item (fn, struct, impl, static, ...) never affects what it does only where it's visible.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.