如何使用函数引用创建一个lazy_static HashMap作为值?

Vic*_*voy 6 rust

我试图HashMap用函数创建一个值:

#[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()
}
Run Code Online (Sandbox Code Playgroud)

编译器给我一个错误:

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
Run Code Online (Sandbox Code Playgroud)

我不明白我该怎么做才能解决这个错误,我不知道有什么其他方法来创建这样的错误HashMap.

She*_*ter 9

您的代码有多个问题.编译器提供的错误告诉您,您的代码将使内存不安全:

`std::ops::Fn([u8]) + 'static` cannot be shared between threads safely
Run Code Online (Sandbox Code Playgroud)

您存储在您的类型HashMap并不能保证它可以共享.

您可以通过将值类型更改为指定此类限制来"修复"该问题&'static (Fn([u8]) + Sync).这会解锁下一个错误,因为您的功能签名不匹配:

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}>`
Run Code Online (Sandbox Code Playgroud)

"修复" &'static (Fn(&[u8]) -> String + Sync)导致了深奥的高度终身错误:

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}>`
Run Code Online (Sandbox Code Playgroud)

这可以通过强制转换函数来"修复" &md5 as &'static (Fn(&[u8]) -> String + Sync)),这导致了

note: borrowed value must be valid for the static lifetime...
note: consider using a `let` binding to increase its lifetime
Run Code Online (Sandbox Code Playgroud)

这是最低的,因为您所做的参考是一个不在范围之外的临时值.


我把修复引入恐慌报价,因为这不是真正正确的解决方案.正确的是只使用一个函数指针:

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
    };
}
Run Code Online (Sandbox Code Playgroud)

老实说,我会说a HashMap可能是矫枉过正; 我会用一个数组.一个小数组可能比一个小数组快HashMap:

type HashFn = fn(&[u8]) -> String;

static HASHES: &'static [(&'static str, HashFn)] = &[
    ("md5", md5),
];
Run Code Online (Sandbox Code Playgroud)

您可以从遍历列表开始,或者可能是花哨的并按字母顺序排列它然后binary_search在它变得更大时使用.