Hi,
I'm new in Rust and I stuck with share my config in application.
In main function, I'm creating config object, whre config file is read and it returns my Settings object:
fn main() -> Result<(), Box<dyn Error>> {
//...
let config = match gurita_core::get_config(matches) {
Ok(settings) => Box::new(settings),
Err(e) => {
println!("Error: {}", e);
std::process::exit(111);
}
};
// ....
// Here I need to call fuction from any module (this time from lib.rs) which
// needs some data from config but I don't want to pass confing into all
// function which needs config
let res = example_function();
println!("{:#?}", res);
Ok(())
}
Now in my lib.rs
pub fn example_function() -> String {
// here I need my config
let ttl = config.jwt.ttl;
// some logic
String::from(result_of_logic)
}
I don't have good answer for it I also don't have much experience in rust but I want to change it. Lets assume, that I'm writting some "nested" module and one of its function needs some "global data" which are initialized in main function. And now I have to insert this global to each function/object which leads to this function in module. main() config ->funct_mod1(&config) -> f_mod2(&config) -> ... -> nested_mod_funct(&config, arg1, arg2)
This looks complicated. I think it would be better to get config directry from last function.
pub fn nested_mod_funct() {
// I need config so I grab it
let config = global::get_my_config();
}
I'd like to create "global variable" which I'll be able to get it from any place in code and I don't know if it is possible.
Maybe there is better solution to share data betwen modules/crates?
Global state often has the illusion of simplicity, but then you're really hiding what your dependencies are. Passing arguments where needed is simple to do. If it's immutable configuration data, it's a matter of passing a reference &config everywhere it's needed.
If passing that configuration around manually feels clunky then I'd argue that's a good thing!
What you are experiencing is your code tell you that it's too coupled and that you are passing a lot of state around your application. You can definitely make the pain go away by using global variables, but the core problem remains.
If lazy_static doesn't suit your needs, perhaps consider turning the design inside out:
Have a struct that holds the configuration
Make your currently free functions methods on this struct
If you have other structs already which use the config in their methods, add the config type to those structs as well
Then instead of functions changing their behavior based on some outside state, you'll have a configuration context within which functions (methods) can run.
Thank you very much, I think that I'm starting understatd it My approach wasn't right. This example does't solve my problem. I don't need to implement new methods to my Settings but just read its data.
mod elsewhere {
use crate::settings::Settings;
pub fn print_settings() {
let s = ???? // Here I need my example object
prlintln!("{:?}",s);
}
}
fn main() {
use settings::Settings;
use elsewhere::*;
let example = Box::new(Settings::new("Hello, world!".into()));
}
In PHP we have static methods which can be use to share the same object. We can call it and if object is intitalized it returns it, if not it create new object.
class Settings {
private static $db;
public static function getInstance()
{
if (self::$db === null) {
// Do some logic
self::$db = self::new();
}
return self::$db;
}
}
After this we have one and only one instance of class in whole application.
Can we do this in Rust?