This question already has an answer here:
Rust Can't import Singleton From global space into another module in another file
(1 answer)
Closed 4 years ago.
I am trying to use the lazy_static crate to create a singleton and use it in a different module. Is that possible or even recommended? I'm still learning how Rust programs should be structured and have been making every file its own module.
I have the following in main.rs and I can access its values
lazy_static! {
static ref GAMEDATA: gamedata::data::GameDataS =
gamedata::data::load_data("./src/assets/data.json".to_string());
}
fn main() {
println!("data{}", GAMEDATA.width);
}
When trying to access GAMEDATA in a different module, I get
not found in this scope
for example in a module called game
pub struct Game {}
impl Game {
println!("data{}", GAMEDATA.width);
}
Is it possible to make a global variable across all modules? Is there some other way I should be thinking about it? Perhaps not using modules as often?
If your static variable is in another non-parent module, your problem seems to be a missing pub modifier before static. Also, as others pointed out, the code in which you use the variable (the impl block) is not valid Rust syntax.
Besides that, you will need to import the static variable with use (E.g. use GAMEDATA;), see Quan Brew's answer.
However, I want to discuss about the use of static and singleton pattern in Rust.
Static variables in Rust
In Rust we generally avoid static variables. In most cases they could be replaced with a proper constant via const. Because static variables may be shared between threads, having them with external mutability is unsafe in Rust. This is why you cannot have external mutability with lazy_static.
Although statics with external mutability do have their uses, they are kind of specific, should be justified and avoided otherwise. Interior mutability, as described in this section of the Rust Book is not even allowed to be shared among threads.
Singleton Pattern in Rust
I don't think it is a good idea to use static to have singleton pattern. This pattern is not common in Rust. We generally pass all mutable things as arguments.
Solutions if you need immutable data
Make it a constant with const.
If there is too much data, use static.
If you need non-constant initialization, you can keep lazy_static.
Solutions if you need to mutate data
Put your singleton into a Mutex or another lock. This will ensure correct concurrent accesses.
Make it thread local with thread_local macro + inner mutability with RefCell
Give up the "singleton pattern" idea and pass the structure via arguments (recommended).
You need use to import GAMEDATA into the current scope, as described in the modules section in the book.
Example code (playground):
#[macro_use]
extern crate lazy_static; // 1.1.0
lazy_static! {
static ref GAMEDATA: String = "hello".to_string();
}
mod foo {
use GAMEDATA;
pub fn bar() {
println!("{}", *GAMEDATA);
}
}
fn main() {
foo::bar();
}
However, the singleton pattern is not recommended in Rust. For beginners in the learning phase, you'd best avoid singletons. (see bzim's answer)
Related
I'm trying to load JSON files that refer to structs implementing a trait. When the JSON files are loaded, the struct is grabbed from a hashmap. The problem is, I'll probably have to have a lot of structs put into that hashmap all over my code. I would like to have that done automatically. To me this seems to be doable with procedural macros, something like:
#[my_proc_macro(type=ImplementedType)]
struct MyStruct {}
impl ImplementedType for MyStruct {}
fn load_implementors() {
let implementors = HashMap::new();
load_implementors!(implementors, ImplementedType);
}
Is there a way to do this?
No
There is a core issue that makes it difficult to skip manually inserting into a structure. Consider this simplified example, where we simply want to print values that are provided separately in the code-base:
my_register!(alice);
my_register!(bob);
fn main() {
my_print(); // prints "alice" and "bob"
}
In typical Rust, there is no mechanism to link the my_print() call to the multiple invocations of my_register. There is no support for declaration merging, run-time/compile-time reflection, or run-before-main execution that you might find in other languages that might make this possible (unless of course there's something I'm missing).
But Also Yes
There are third party crates built around link-time or run-time tricks that can make this possible:
ctor allows you to define functions that are executed before main(). With it, you can have my_register!() create invididual functions for alice and bob that when executed will add themselves to some global structure which can then be accessed by my_print().
linkme allows you to define a slice that is made from elements defined separately, which are combined at compile time. The my_register!() simply needs to use this crate's attributes to add an element to the slice, which my_print() can easily access.
I understand skepticism of these methods since the declarative approach is often clearer to me, but sometimes they are necessary or the ergonomic benefits outweigh the "magic".
I have a project with its own error type, which is exposed outside of crate. Lets call it MyErrorType. The project itself internally depends on another crate with its own error type. Lets call it ForeignErrorType.
In order to simplify code and make it more readable I've created following implementation of From trait:
impl From<ForeignErrorType> for MyErrorType {
...
}
This allows to use question mark operator, ?, when dealing with foreign error types without a necessity to convert them in place.
The issue is that the mentioned trait implementation is exposed outside of my crate. I don't want the users of my crate to accidentally rely on the conversion possibility from ForeignErrorType to MyErrorType.
What I've tried so far: Have put the mentioned trait implementation into module with pub(crate) visibility. This surprisingly hides all structs defined in such module, but leaves trait implementation exposed.
Is there way to keep my From implementation private and not to expose it outside of crate?
Probably I'm trying to achieve error handling benefits in a non‑idiomatic way. If this is true, what's the proper way to be able to use ? operator on foreign error types without exposing them?
Is there way to keep my From implementation private and not to expose it outside of crate?
No. Trait implementations have no scope.
What you can do instead in this case is write a function with the same contents as your From implementation would have had, and apply it with Result::map_err before ?.
pub(crate) fn foreign_err(e: ForeignErrorType) -> MyErrorType {
todo!()
}
...
let foo = their_function().map_err(foreign_err)?;
This has to be done at every ? usage, but there is no way to have an implicit conversion that is scoped to a crate or module, so that's the best you can have.
I am currently implementing my first library in Rust, and as it is the case with many developers coming from other languages like Java etc. I am struggling to find right solutions for common patterns/use cases in Rust.
My Rust library has multiple structs. Many of them need to have access to some common configuration options which are essential for their function. For example:
pub struct A {
pub context: Context
}
pub struct B {
pub context: Context
}
pub struct Context {
pub dbUri: String
}
The context will be passed to each struct once when the struct is initialized. The context attribute values might change at runtime which should make these changes available to any dependent struct. Structs should be able to make changes to context if required. It might be required to make the context available to different threads in the future.
The best solution I could find so far is to use Mutex wrapped in Arc as described here.
I would like to know whether this is the right way to implement my requirement, and what are other available options?
In The Rust Programming Language, it says something like:
Move semantics
There’s some more subtlety here, though: Rust ensures that there is
exactly one binding to any given resource. For example, if we have a
vector, we can assign it to another binding:
But I found that I can do this using gtk-rs:
let label1: gtk::Label = builder.get_object("label1").unwrap();
let label1_test: gtk::Label = builder.get_object("label1").unwrap();
Both now point to the same resource "or something happens to me."
Builder::get_object is defined as:
pub fn get_object<T: IsA<Object>>(&self, name: &str) -> Option<T> {
unsafe {
Option::<Object>::from_glib_none(
ffi::gtk_builder_get_object(self.to_glib_none().0, name.to_glib_none().0))
.and_then(|obj| obj.downcast().ok())
}
}
Although this is not really something from Rust directly, just from gtk-rs, I was wondering if I am right and how sure is this.
Maybe it could use Rc?
GTK/GLib objects (GObject) implement reference counting directly, similar to the Arc type in Rust. You can safely have multiple references to the same object, and once the last one goes out of scope the object will be destroyed.
For mutability, in Rust, gtk-rs uses interior mutability (conceptually). So you can mutate every reference to the same object, even if there are multiple of them. The implementation of the objects has to handle that (and has to anyway because that's how things work in GTK/GLib in C).
I'm toying with the cgmath library. I have the following main.rs file:
extern crate cgmath;
use cgmath::vector::{Vector3, EuclideanVector};
fn main() {
let mypoint = Vector3 { x: 1f64, y: 1f64, z: 3f64 };
println!("The length of the vector is {}, and the length squared is {}", mypoint.length(), mypoint.length2());
}
In my use line, when I omit EuclideanVector, I am given the following compilation error:
type 'cgmath::vector::Vector3<f64>' does not implement any method in scope named 'length'
It appears that the Rust compiler cannot find the length() method unless I import one of the traits that Vector3 uses. Delving into the source code, it looks like the length method is defined within the EuclideanVector trait.
Intuitively, I should not need to import an trait to use a type that inherits said trait. Is there a technique to do so that I am missing? Is this a nuance specific to the cgmath library? Is this an idiomatic part of Rust that I should become accustomed to?
You're thinking of traits in terms of inheritance. It might make more sense if you think of a trait as a module that's overloadable with respect to the Self type. From this perspective, it makes sense that the trait has to be in scope in order for the compiler to know about its methods, just as a module has to be in scope in order to use it. A particular implication of this is that implementations can be declared alongside the trait they implement rather than the type they implement it for. In this situation, clearly if your code doesn't know about the trait, it can't use its methods.
Another motivation for the current behaviour is that multiple traits can define methods with the same name, and when you have such a conflict for traits implemented for the same type, you can no longer use method call syntax to access their methods. Instead, you have to use function call syntax in order to specify which trait the method is a member of (the trait acting as the module the method is in). If method call syntax used all traits in your program rather than just the ones in scope for method resolution, you'd end up with these conflicts much more often, since you'd have name conflicts with methods in traits that your code isn't actually using directly.
Strictly speaking, you don't have to use use. Alternatively:
(&mypoint as &cgmath::vector::EuclideanVector).length2()
Yes, this is how Rust works. You must always import a trait before you can use its methods. This is by design.
If you really don't want to import, you can call cgmath::vector::EuclideanVector::length(&mypoint).
(I don't know if this was possible when the question was asked.)