Сообщение об ошибке говорит о том, что вы не можете десериализовать до &'static str
.Поскольку десериализатор продолжает создавать записи, ключи &str
могут иметь столько же времени жизни, сколько заимствовано из буфера, в который десериализатор читает файл.Но &'static str
должен указывать на str
, который живет вечно.
Здесь я вижу два решения: легкий и трудный путь.
легкий путь: просто поменяйте &'static str
в типе String
и он компилируется.Таким образом, HashMap
владеет ключами;serde уже знает, как десериализовать собственные строки.
static ref KEYWORDS: HashMap<String, i32> = { // ...
Сложный путь: Технически вы все еще можете получить свой HashMap<&'static str, i32>
, пропуская резервные буферы String
s.Обычно «утечка» - это плохо, но, поскольку это ленивая статика, это действительно не имеет значения, так как эти буферы никогда не будут освобождены.Получение &'static str
путем утечки String
выглядит следующим образом:
fn leak_string(from: String) -> &'static str {
Box::leak(from.into_boxed_str())
}
Проблема в том, что serde не делает этого автоматически.Один из способов сделать это - сначала десериализовать в HashMap<String, i32>
, а затем преобразовать в HashMap<&'static string, i32>
, взяв каждую из записей и вставив их в новый HashMap
после запуска ключей через leak_string
.Это неэффективно, так как не было необходимости собирать в HashMap
в первую очередь.Лучшим решением было бы написать собственный десериализатор, который выполнял бы leak_string
«на лету».Поскольку легкий путь намного проще, и для этого трудного пути есть несколько камней преткновения, я не думаю, что здесь будет полезен полный пример кода.
Единственное реальное преимущество «трудного пути»По сравнению с «простым способом», «сложный путь» требует меньше памяти на один указатель для каждой клавиши в HashMap
(&str
- указатель + len; String
- указатель + len + емкость).Приятно также и то, что он не меняет сигнатуру вашего типа, но вы мало что можете сделать с &'static str
, чего не можете сделать с String
.