In Rust gibt es keine Map-Literal-Syntax. Ich kenne den genauen Grund nicht, aber ich gehe davon aus, dass die Tatsache, dass es mehrere Datenstrukturen gibt, die maplike wirken (wie beide BTreeMap
und HashMap
), es schwierig machen würde, eine auszuwählen.
Sie können jedoch ein Makro erstellen, um die Aufgabe für Sie zu erledigen, wie unter Warum funktioniert dieses rostige HashMap-Makro nicht mehr? . Hier ist das Makro ein wenig vereinfacht und mit genügend Struktur, um es auf dem Spielplatz laufen zu lassen :
macro_rules! map(
{ $($key:expr => $value:expr),+ } => {
{
let mut m = ::std::collections::HashMap::new();
$(
m.insert($key, $value);
)+
m
}
};
);
fn main() {
let names = map!{ 1 => "one", 2 => "two" };
println!("{} -> {:?}", 1, names.get(&1));
println!("{} -> {:?}", 10, names.get(&10));
}
Dies hat keine zusätzliche Zuordnung und ist maximal effizient.
In einer nächtlichen Version von Rust können Sie sowohl unnötige Zuweisungen als auch die Notwendigkeit eines Makros vermeiden :
#![feature(array_value_iter)]
use std::array::IntoIter;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::iter::FromIterator;
fn main() {
let s = Vec::from_iter(IntoIter::new([1, 2, 3]));
println!("{:?}", s);
let s = BTreeSet::from_iter(IntoIter::new([1, 2, 3]));
println!("{:?}", s);
let s = HashSet::<_>::from_iter(IntoIter::new([1, 2, 3]));
println!("{:?}", s);
let s = BTreeMap::from_iter(IntoIter::new([(1, 2), (3, 4)]));
println!("{:?}", s);
let s = HashMap::<_, _>::from_iter(IntoIter::new([(1, 2), (3, 4)]));
println!("{:?}", s);
}
Diese Logik kann dann auch wieder in ein Makro eingeschlossen werden:
#![feature(array_value_iter)]
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
macro_rules! collection {
($($k:expr => $v:expr),* $(,)?) => {
std::iter::Iterator::collect(std::array::IntoIter::new([$(($k, $v),)*]))
};
($($v:expr),* $(,)?) => {
std::iter::Iterator::collect(std::array::IntoIter::new([$($v,)*]))
};
}
fn main() {
let s: Vec<_> = collection![1, 2, 3];
println!("{:?}", s);
let s: BTreeSet<_> = collection! { 1, 2, 3 };
println!("{:?}", s);
let s: HashSet<_> = collection! { 1, 2, 3 };
println!("{:?}", s);
let s: BTreeMap<_, _> = collection! { 1 => 2, 3 => 4 };
println!("{:?}", s);
let s: HashMap<_, _> = collection! { 1 => 2, 3 => 4 };
println!("{:?}", s);
}
Siehe auch:
grabbag_macros
Kiste. Sie können die Quelle hier sehen: github.com/DanielKeep/rust-grabbag/blob/master/grabbag_macros/… .DictionaryLiteral
kann verwendet werden, um jeden Typ zu initialisieren, der dem entsprichtExpressibleByDictionaryLiteral
(obwohl die Standardbibliothek einen solchen Typ anbietetDictionary
)Ich empfehle die Maplit- Kiste.
Um aus der Dokumentation zu zitieren:
use maplit::hashmap; let map = hashmap!{ "a" => 1, "b" => 2, };
quelle
In der Dokumentation finden Sie
HashMap
ein Beispiel dafür :let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] .iter() .cloned() .collect();
quelle
String
anstelle von verwenden&str
.vec![ (name, value) ].into_iter().collect()
Wie von @Johannes in den Kommentaren erwähnt, ist es möglich, Folgendes zu verwenden
vec![]
:Vec<T>
implementiert dasIntoIterator<T>
MerkmalHashMap<K, V>
GeräteFromIterator<Item = (K, V)>
was bedeutet, dass Sie dies tun können:
let map: HashMap<String, String> = vec![("key".to_string(), "value".to_string())] .into_iter() .collect();
Sie können verwenden, müssen
&str
jedoch möglicherweise Lebensdauern mit Anmerkungen versehen, wenn dies nicht der Fall ist'static
:let map: HashMap<&str, usize> = vec![("one", 1), ("two", 2)].into_iter().collect();
quelle
Für ein Element
Wenn Sie die Karte mit nur einem Element in einer Zeile (und ohne sichtbare Mutation in Ihrem Code) initialisieren möchten, können Sie Folgendes tun:
let map: HashMap<&'static str, u32> = Some(("answer", 42)).into_iter().collect();
Dies ist der Nützlichkeit zu verdanken,
Option
eineIterator
Verwendung werden zu könneninto_iter()
.In echtem Code müssen Sie dem Compiler wahrscheinlich nicht mit dem Typ helfen:
use std::collections::HashMap; fn john_wick() -> HashMap<&'static str, u32> { Some(("answer", 42)).into_iter().collect() } fn main() { let result = john_wick(); let mut expected = HashMap::new(); expected.insert("answer", 42); assert_eq!(result, expected); }
Es gibt auch eine Möglichkeit, dies zu verketten, damit mehr als ein Element so etwas tut.
Some(a).into_iter().chain(Some(b).into_iter()).collect()
Dies ist jedoch länger, weniger lesbar und weist wahrscheinlich einige Optimierungsprobleme auf. Ich rate daher davon ab.quelle
Ich habe eine Reihe ausgefallener Lösungen gesehen, aber ich wollte nur etwas Einfaches. Zu diesem Zweck ist hier eine Eigenschaft:
use std::collections::HashMap; trait Hash { fn to_map(&self) -> HashMap<&str, u16>; } impl Hash for [(&str, u16)] { fn to_map(&self) -> HashMap<&str, u16> { self.iter().cloned().collect() } } fn main() { let m = [("year", 2019), ("month", 12)].to_map(); println!("{:?}", m) }
Ich denke, es ist eine gute Option, da es im Wesentlichen das ist, was Ruby und Nim bereits verwenden:
quelle
copied()
Typ zu verbieten, der keine Kopie implementiert, das Klonen umsonst zu vermeiden oder es zumindest mit cloned_to_map () explizit zu machen, wenn Sie dies auch nur mit geklontem Typ tun möchten.