2017-04-09 3 views
3

Ich habe versucht, eine HashMap mit Funktionen wie die Werte zu schaffen:Wie erstellt man eine lazy_static HashMap mit Funktionsreferenzen als Wert?

#[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() 
} 

Der Compiler gibt mir eine Fehlermeldung:

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 

Ich verstehe nicht, was soll ich diesen Fehler zu beheben tun und ich kenne keine andere Möglichkeit, eine solche HashMap zu erstellen.

Antwort

6

Ihr Code weist mehrere Probleme auf. Der Fehler vom Compiler präsentiert sagt Ihnen, dass Ihr Code, Speicher unsafety erlaubt:

`std::ops::Fn([u8]) + 'static` cannot be shared between threads safely 

Der Typ, den Sie in Ihrem HashMap sind die Speicherung hat keine Garantie, dass sie geteilt werden können.

Sie können das beheben, indem Sie eine solche Grenze angeben, indem Sie Ihren Werttyp in &'static (Fn([u8]) + Sync) ändern. Dies entriegelt die nächste Fehler, aufgrund der Tatsache, dass Ihre Funktion Signaturen nicht übereinstimmen:

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}>` 

„Fixing“ dass mit &'static (Fn(&[u8]) -> String + Sync) führt zu esoterisch höherer kinded Lebensdauer Fehler:

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}>` 

Welche kann mit &md5 as &'static (Fn(&[u8]) -> String + Sync)) durch Gießen der Funktion „fixiert“ werden, die wegen the reference you've made is to a temporary value that doesn't live outside of the scope

note: borrowed value must be valid for the static lifetime... 
note: consider using a `let` binding to increase its lifetime 

Dieser anstößt zu

führt.


Ich legte fest in Schrecken Zitate, weil dies nicht wirklich die richtige Lösung ist. Das Richtige ist, nur einen Funktionszeiger zu verwenden:

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 
    }; 
} 

Ehrlich gesagt, ich würde sagen, dass ein HashMap ist wahrscheinlich übertrieben; Ich würde ein Array verwenden. Ein kleines Array ist wahrscheinlich schneller als ein kleines HashMap:

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

static HASHES: &'static [(&'static str, HashFn)] = &[ 
    ("md5", md5), 
]; 

Sie von nur Iterieren durch die Liste beginnen können, oder vielleicht Lust, und es alphabetize und dann binary_search verwenden, wenn es ein bisschen größer wird.

Verwandte Themen