A generic struct Foo<T> may need a generic global variable associated with the same T instantiated. Something like
/// library code
static mut FOO<T>: Option<Vec<T>> = None;
And for all instantiations of FOO::<T> there exists a global variable of the type Option<Vec<T>>. For example:
/// client code
let i32s_inited = FOO::<i32>.is_some(); // type annotation
let first_str: String = FOO // type inference
.map( |foo| foo.first()
.map( |s| s.clone() )
.unwrap_or_default() )
.unwrap_or_default();
will produce two global variables, as if they have been declared previously:
/// library code
// not valid identifiers, just for demonstration
static mut FOO::<i32> : Option<Vec<i32>> = None;
static mut FOO::<String> : Option<Vec<String>> = None;
Since it’s not valid Rust syntax right now, we have to use trait as alternative to achieve similar result:
/// library code
pub trait GlobalFoo where Self: Sized {
fn foo() -> &'static mut Option<Vec<Self>> {
unimplemented!()
}
}
pub struct Foo<T> { /* omitted */ }
impl<T> Foo<T> where T: 'static + GlobalFoo
{
fn using_generic_global( &self ) {
let foo = T::foo();
// omitted
}
}
/// client code
static mut FOO_I32: Option<Vec<i32>> = None;
static mut FOO_STRING: Option<Vec<String>> = None;
impl GlobalFoo for i32 {
fn foo() -> &'static mut Option<Vec<i32>> {
&mut FOO_I32
}
}
impl GlobalFoo for String {
fn foo() -> &'static mut Option<Vec<String>> {
&mut FOO_STRING
}
}
let i32_foo = Foo::<i32>::new();
i32_foo.using_generic_global();
let string_foo = Foo::<String>::new();
string_foo.using_generic_global();
The alternative method is more verbose.
So, is it worth introducing “generic global variables”?