Module/Crate level mutable variables

I am giving myself a project to better learn Rust, and an easy one is a country/locale program, similar to the Perl Locale::Country module (which I use regularly). I have a module-level variable, initialized at compile-time, that looks like this:

static COUNTRIES: &'static str =
"Afghanistan|AF|AFG|004|Asia
Åland Islands|AX|ALA|248|Europe
Albania|AL|ALB|008|Europe
Algeria|DZ|DZA|012|Africa" ...

Each line maps to a struct:

struct Country {
name: String,
alpha_2: String,
alpha_3: String,
code: String,
region: String
}

Example calls would look like:
let country = code_to_country("AL") -> "Albania"
let c2 = code_to_country("dza") -> "Algeria"
let c3 = code_2_country("008") -> "Albania"
let c4 = country_to_region("albania") -> "Europe"

etc.

For faster lookups, I thought of splitting COUNTRIES into various associative arrays (one keyed on alpha_2, another keyed on alpha_3, etc. all populated just once, when the first lookup is performed). At present, I'm using split() on newlines in COUNTRIES, then using split("|") to break each line into separate fields. I realise there are probably much smarter ways to do this, but for now I'm just learning the ins-and-outs of Rust programming. I'll worry about elegance later :slight_smile:

On thinking about it, I think I may be imposing my old Perl habits on Rust, so I'm probably doing this all wrong. What is the correct Rust-ish way of looking at this? Because its compiled, do I simply let the lookup program do a brute-force search through COUNTRIES? Can I load module-level static vectors or hashes at module-load time?

Thanks for your thoughts.

Dean Powell
Edmonton, Canada

You can have static vecs/hashmaps using the lazy_static crate.
If you want to do the splitting at runtime, you could have something like:

const COUNTRIES_RAW: &'static str =
"Afghanistan|AF|AFG|004|Asia
...";

lazy_static! {
    static ref COUNTRIES: Vec<Country> = {
        COUNTRIES.lines().map(|s| {
            let mut parts = s.split("|");
            // Build & return your `Country` from `parts`
        }).collect()
    };
}

Though if a Country is always going to have its parts read from this static string, I'd define it having &str fields instead of Strings.

Building indexes over your country dataset could be useful, but it really depends on how much work you're doing. If you're only looking up a couple of things per program invocation, it's not really worth it to index, since it'd take longer to traverse the whole thing to build the index than it would to just find whatever you're looking for through regular iteration.

1 Like