Тонкость в этом заключается с двойной реализацией IntoIterator
для BTreeMap
(и большинства коллекций на самом деле). Вы можете увидеть это в документации , в следующем порядке:
impl<K, V> IntoIterator for BTreeMap<K, V>
Это ваш первый случай. То, что вы делаете, это перемещаете BTreeMap
и потребляете его для создания (K, V)
итератора. Вы можете убедиться в этом с помощью следующего фрагмента:
let mut my_btree:BTreeMap<i64, String> = BTreeMap::new();
my_tree.insert(3, "this is a test".to_string());
let mut rows = Vec::new();
for (k, v) in my_btree { // BTreeMap<i64, String>
rows.push((k, v))
}
Это потребляет my_btree
и дает (K, V)
пар, одну за другой. Так как эти пары принадлежат , вы можете спокойно вставить их в Vec
, который вы указали. В вашем фрагменте у вас было &k
и &v
- и эти ссылки никогда не будут работать, так как элементы будут немедленно выброшены из области видимости.
impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V>
Это ваш второй случай. В этом случае ваш итератор теперь (&'a K, &'a V)
, и вы можете легко убедить себя в этом, пытаясь вывести Vec
из области действия BTreeMap
, например, так:
fn does_not_work<'a>() -> Vec<(&'a i64, &'a String)> {
let my_btree:BTreeMap<i64, String> = BTreeMap::new();
let mut rows = Vec::new();
for (k, v) in &my_btree { // BTreeMap<i64, String>
rows.push((k, v))
}
rows
}
Это будетне компилировать, потому что вы вставили кучу ссылок на элементы в BTreeMap
, а затем отбросили его (из-за того, что он вышел из области видимости) - все эти ссылки будут недействительными, если средство проверки заимствования не придет на помощь.
Итак, в этом и заключается разница - в одном случае вы используете BTreeMap
для работы с собственными структурами, в другом - с ссылками.
Ваш пример функционирует из-заэто - вы никогда не разыменовываете карту из-за итератора &ss.x
, который никогда не использует карту.