How to create lazy_static HashMap with function reference as value?
I tried to create HashMap
with functions as values:
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
lazy_static! {
static ref HASHES: HashMap<&'static str, &'static Fn([u8])> = {
let mut m = HashMap::new();
m.insert("md5", &md5);
m
};
}
fn md5(bytes: &[u8]) -> String {
String::default()
}
The compiler is giving me an error:
error[E0277]: the trait bound `std::ops::Fn([u8]) + 'static: std::marker::Sync` is not satisfied in `&'static std::ops::Fn([u8]) + 'static` --> src/main.rs:6:1 | 6 | lazy_static! { | _^ starting here... 7 | | static ref HASHES: HashMap<&'static str, &'static Fn([u8])> = { 8 | | let mut m = HashMap::new(); 9 | | m.insert("md5", &md5); 10 | | m 11 | | }; 12 | | } | |_^ ...ending here: within `&'static std::ops::Fn([u8]) + 'static`, the trait `std::marker::Sync` is not implemented for `std::ops::Fn([u8]) + 'static` | = note: `std::ops::Fn([u8]) + 'static` cannot be shared between threads safely = note: required because it appears within the type `&'static std::ops::Fn([u8]) + 'static` = note: required because of the requirements on the impl of `std::marker::Sync` for `std::collections::hash::table::RawTable<&'static str, &'static std::ops::Fn([u8]) + 'static>` = note: required because it appears within the type `std::collections::HashMap<&'static str, &'static std::ops::Fn([u8]) + 'static>` = note: required by `lazy_static::lazy::Lazy` = note: this error originates in a macro outside of the current crate
I don’t understand what should I do to fix this error and I don’t know of any other way to create such HashMap
.
source to share
There are several problems in your code. The error presented by the compiler tells you that your code will avoid memory insecurity:
`std::ops::Fn([u8]) + 'static` cannot be shared between threads safely
The type that you store in HashMap
does not guarantee that it can be generic.
You can "fix" this by specifying such a binding by changing the value type to &'static (Fn([u8]) + Sync)
. This will unlock the following error due to your function signatures not matching:
expected type `std::collections::HashMap<&'static str, &'static std::ops::Fn([u8]) + std::marker::Sync + 'static>` found type `std::collections::HashMap<&str, &fn(&[u8]) -> std::string::String {md5}>`
The "fixation" which, with help, &'static (Fn(&[u8]) -> String + Sync)
leads to the esoteric errors of life of a higher order:
expected type `std::collections::HashMap<&'static str, &'static for<'r> std::ops::Fn(&'r [u8]) -> std::string::String + std::marker::Sync + 'static>` found type `std::collections::HashMap<&str, &fn(&[u8]) -> std::string::String {md5}>`
Which can be "fixed" by discarding the function with &md5 as &'static (Fn(&[u8]) -> String + Sync))
, which results in
note: borrowed value must be valid for the static lifetime... note: consider using a `let` binding to increase its lifetime
This means that the link you made refers to a temporary value that does not live outside the scope .
I am putting the fix in quotes because it is not exactly the right solution. It is correct to use a function pointer:
lazy_static! {
static ref HASHES: HashMap<&'static str, fn(&[u8]) -> String> = {
let mut m = HashMap::new();
m.insert("md5", md5 as fn(&[u8]) -> std::string::String);
m
};
}
To be honest, I'd say it HashMap
's probably overkill; I would use an array. A small array is probably faster than a small one HashMap
:
type HashFn = fn(&[u8]) -> String;
static HASHES: &'static [(&'static str, HashFn)] = &[
("md5", md5),
];
You can start by simply iterating over the list, or maybe represent it alphabetically as well, and then use binary_search
it when it gets more bits.
source to share