Assuming that we need to define a singleton with global read access with thread safety, the canonical method is to use OnceLock:
/// A synchronization primitive which can be written to only once.
///
/// This type is a thread-safe [`OnceCell`], and can be used in statics.
static i1: OnceLock<Box<u64>> = OnceLock::new(); // this works
static i2: OnceLock<Box<dyn Sized>> = OnceLock::new(); // this doesnt:
the second line throw several errors that doesn't make sense:
error[E0038]: the trait `Sized` cannot be made into an object
--> src/lib.rs:118:25
|
118 | static i2: OnceLock<Box<dyn Sized>> = OnceLock::new();
| ^^^^^^^^^ `Sized` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
Sized is a trait that has dynamic size, but Box is just a smart reference that points to a dynamically allocated struct later, and it is not even initialised in this definition, so why do I need make it into an object?
error[E0277]: `(dyn Sized + 'static)` cannot be shared between threads safely
--> src/lib.rs:118:12
|
118 | static i2: OnceLock<Box<dyn Sized>> = OnceLock::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Sized + 'static)` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `(dyn Sized + 'static)`
= note: required for `Unique<(dyn Sized + 'static)>` to implement `Sync`
note: required because it appears within the type `Box<(dyn Sized + 'static)>`
--> /home/peng/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:195:12
|
195 | pub struct Box<
| ^^^
= note: required for `OnceLock<Box<(dyn Sized + 'static)>>` to implement `Sync`
= note: shared static variables must have a type that implements `Sync`
"Thread Safety" & "static" are literally in the documentation of "OnceLock", how could it be considered unsafe?
error[E0277]: `(dyn Sized + 'static)` cannot be sent between threads safely
--> src/lib.rs:118:12
|
118 | static i2: OnceLock<Box<dyn Sized>> = OnceLock::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Sized + 'static)` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `(dyn Sized + 'static)`
= note: required for `Unique<(dyn Sized + 'static)>` to implement `Send`
note: required because it appears within the type `Box<(dyn Sized + 'static)>`
--> /home/peng/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/boxed.rs:195:12
|
195 | pub struct Box<
| ^^^
= note: required for `OnceLock<Box<(dyn Sized + 'static)>>` to implement `Sync`
= note: shared static variables must have a type that implements `Sync`
any static binding only has 1 replica in memory and is used by all threads in a process, there is no need to send them between threads like some distributed computing framework. How could the compiler never realised that?
So these 3 errors all appears to be clueless, how can I bypass these errors and make the static binding work with minimal overhead?
dyn Sizedcontradicts itself,Sizedmeans, all items of a type have a statically known size, butSizedis implemented for a variety of types,(),u8,u16, … all with a different size, that meansdyn Sizedcould have a size of 0 bytes, 1 byte, 2 bytes, … and you can change the underlying type at runtime so it is not statically known. That means a trait object (because it can be any type it's trait is implemented for) cannot implementSized, but implementing the named trait is all we know a trait object does. In other wordsdyn Sizeddoes not implementSizedbut must implementSizedat the same time.The second and third error boil down to
staticsneeding to beSync(they can be accessed from any thread andSyncis the trait that tells the compiler it's safe to do so) butOnceCellonly implementsSyncif it's contents areSync + Send. The source ofOnceCellexplains*:A trait object however only implements the traits it lists, so
dyn Traitdoes not implement eitherSendorSync.You can achive what you seem to want simply by specifying an object safe trait and add the
SendandSyncbounds to the trait object as well. For example withstd::any::Anyfor anyT: 'statictype:*) That doesn't apply for your specific case, but does explain why
OnceCellneeds it's content to implementSend, to get around it one would need a distinctLeakingOnceCellwhich does not drop it's contents, it's usefulness seems questionable to me.