you are correct that each closure has its own type. they can, however, coerce to function types if they are captureless. but coersion only happens if the compiler can figure out the type. unfortunately, the From::from() doesn't provide context in this case. you can explicitly annotate the type, although it is quite verbose because you must specify the length of the array type.
// option1: annotate with named binding
let map_entries: [(&str, fn()->&'static str); 3] = [...];
return HashMap::from(map_entries);
// option 2: annotate with explicit argument for `From` trait
return From::< [(&str, fn()->&'static str); 3] >::from([...]);
another method to provide context for type inference is to use a helper function, like this:
fn() -> &'static str seems suspicious anyway. Is it just for simplified code for the question? If not, why don't you use HashMap<&'static str, &'static str> instead?
if you can include_str!(), that's convinient, but there are rare situations you don't want include_str!() (or include_bytes() for that matter) but prefer Box::leak(), for instance, due to some API limitations, or because the data is HUGE, or because the data cannot baked into the binary and might be edited outside your program.
that being said, &'static str should be suffient most of the time, though a fn can be a valid use case if laziness does make sense (for instance the potential data set is huge but only sparsely used each run)
include_str! is a macro that resolves to the contents of the given filename at compile time. Putting it behind a closure is completely equivalent to just writing || "long string that is present in the file", which serves no apparent purpose.
If you want to read the strings at runtime, use || std::fs::read_to_string(filename) (or one of the Lazy constructs if you don't want to read it multiple times), else just use plain string literals without closures using include_str!.