Am I the only one surprised by this Rust behavior?

52 points ufoscout 34 comments

I expected that, due to generics, a separate instance of ONCE would be generated for each monomorphized version of get_name<T>(). However, it appears that there is only a single static instance being reused across different callers.

My questions are:

  • Am I the only one finding this unexpected?
  • Could someone clarify why my assumption that there should be two distinct instances of ONCE is incorrect?

​

#[test]
fn once_lock_with_generics() {

    use std::sync::OnceLock;

    trait SomeTrait {
        const NAME: &'static str;
    }

    fn get_name<T: SomeTrait>() -> &'static str { 
        static ONCE: OnceLock<&'static str> = OnceLock::new();
        ONCE.get_or_init(|| T::NAME)
    }

    struct SomeStruct1;
    impl SomeTrait for SomeStruct1 {
        const NAME: &'static str = "some-struct-1";
    }

    struct SomeStruct2;
    impl SomeTrait for SomeStruct2 {
        const NAME: &'static str = "some-struct-2";
    }

    // This prints 'some-struct-1'
    println!("SomeStruct1::NAME:       {}", <SomeStruct1 as SomeTrait>::NAME);
    // This prints 'some-struct-1'
    println!("get_name::<SomeStruct1>: {}", get_name::<SomeStruct1>());
    // This prints 'some-struct-2'
    println!("SomeStruct2::NAME:       {}", <SomeStruct2 as SomeTrait>::NAME);

    // This prints 'some-struct-1'!!! WHAT?!? ...confused...
    println!("get_name::<SomeStruct2>: {}", get_name::<SomeStruct2>());
}