2017-08-16 8 views
6

यह किसी भी भाषा में एक छोटा काम होना चाहिए। यह जंग में काम नहीं कर रहा है।हैशमैप के माध्यम से पुनरावृत्ति कैसे करें, कुंजी/मान मुद्रित करें और जंग में मान को हटा दें?

error[E0382]: use of moved value: `*map` 
--> src/main.rs:6:9 
    | 
4 |  for (key, value) in map { 
    |       --- value moved here 
5 |   println!("{}/{}", key, value); 
6 |   map.remove(key); 
    |   ^^^ value used here after move 
    | 
    = note: move occurs because `map` has type `&mut std::collections::HashMap<std::string::String, std::string::String>`, which does not implement the `Copy` trait 

क्यों यह एक संदर्भ स्थानांतरित करने के लिए कोशिश कर रहा है:

use std::collections::HashMap; 

fn do_it(map: &mut HashMap<String, String>) { 
    for (key, value) in map { 
     println!("{}/{}", key, value); 
     map.remove(key); 
    } 
} 

fn main() {} 

यहाँ संकलक त्रुटि है? प्रलेखन से, मुझे नहीं लगता था कि संदर्भों पर चलने/उधार लेने पर लागू किया गया है।

उत्तर

9

वहाँ कम से कम दो कारणों से यह क्यों की अनुमति नहीं है कर रहे हैं:

  1. आप map करने के लिए दो समवर्ती परिवर्तनशील संदर्भ की आवश्यकता होगी - चर map में for पाश और एक में इस्तेमाल किया इटरेटर द्वारा आयोजित एक map.remove पर कॉल करने के लिए।

  2. आपके पास मानचित्र को म्यूटेट करने का प्रयास करते समय मानचित्र के भीतर कुंजी और मूल्य का संदर्भ है। यदि आपको किसी भी तरह से मानचित्र को संशोधित करने की अनुमति दी गई थी, तो इन संदर्भों को अमान्यता के लिए दरवाजा खोलने, अमान्य किया जा सकता है।

एक कोर जंग सिद्धांत एलियासिंग XOR अस्थिरता है। आपके पास मूल्य के लिए कई अपरिवर्तनीय संदर्भ हो सकते हैं या आप इसके लिए एक एकल परिवर्तनीय संदर्भ प्राप्त कर सकते हैं।

I didn't think moving/borrowing applied to references.

प्रत्येक प्रकार जंग के साथ-साथ उत्परिवर्तनीय एलियासिंग के नियमों के अधीन है। कृपया हमें बताएं कि प्रलेखन का कौन सा हिस्सा कहता है कि ऐसा नहीं है इसलिए हम उसे संबोधित कर सकते हैं।

Why it is trying to move a reference?

यह दो भागों से संयुक्त है:

  1. आप केवल एक ही परिवर्तनशील संदर्भ
  2. for छोरों take the value to iterate over by value

जब आप for (k, v) in map {} फोन, map के मालिकाना हक है हो सकता है लूप के लिए स्थानांतरित कर दिया गया है और अब चला गया है।


मैं नक्शा (&*map) के एक अपरिवर्तनीय उधार करते हैं और उस पर पुनरावृति होगी।

fn do_it(map: &mut HashMap<String, String>) { 
    for (key, value) in &*map { 
     println!("{}/{}", key, value); 
    } 
    map.clear(); 
} 

remove every value with a key that starts with the letter "A"

मैं प्रयोग करेंगे HashMap::retain: अंत में, मैं पूरी बात स्पष्ट होता

fn do_it(map: &mut HashMap<String, String>) { 
    map.retain(|key, value| { 
     println!("{}/{}", key, value); 

     !key.starts_with("a") 
    }) 
} 

यह गारंटी देता है कि key और value अब मौजूद नहीं हैं जब नक्शा वास्तव में संशोधित किया गया है , इस प्रकार कोई उधार जो वे चाहते थे अब चला गया है।

+0

मुझे मानचित्र में {कुंजी, मूल्य) के साथ एक ही त्रुटि मिल सकती है {}; मानचित्र में {कुंजी, मान) के लिए {} ', और मुझे नहीं लगता कि यह उत्तर बताता है। –

+1

इसके बारे में सोचने का एक तरीका यह है कि क्या होगा यदि आपने लूप के अंदर 'map.clear() 'कहा था? 'कुंजी 'और' मान' संदर्भ हैं, और वे अब और कुछ भी संदर्भित नहीं करेंगे। उधारकर्ता-चेकर दृष्टिकोण से 'स्पष्ट' और 'निकालें' दोनों का उपयोग 'और mut self'', वे समान हैं। – loganfsmyth

+0

इससे मुझे एक भी मामूली समस्या का सामना करना पड़ा, लेकिन मुझे संदेह है कि विधि कॉल वाक्यविन्यास इस मुद्दे को अस्पष्ट कर रहा है। https://play.rust-lang.org/?gist=ecf6d9bdbe8e1ad99e5fb3c35c402d1c&version=stable –

5

This should be a trivial task in any language.

जंग नक्शा परिवर्तनशील जबकि आप इसे ऊपर पुनरावृत्ति कर रहे हैं से रोक रहा है। अधिकांश भाषाओं में इसकी अनुमति है, लेकिन अक्सर व्यवहार अच्छी तरह से परिभाषित नहीं होता है, और आइटम को हटाने से पुनरावृत्ति के साथ हस्तक्षेप हो सकता है, इसकी शुद्धता समझौता किया जा सकता है।

Why it is trying to move a reference?

HashMapIntoIterator लागू करता है, so your loop is equivalent to:

for (key, value) in map.into_iter() { 
    println!("{}/{}", key, value); 
    map.remove(key); 
} 

आप definition of into_iter को देखें, तो आप देखेंगे कि यह self, नहीं &self या &mut self लेता है। आपका चर map एक संदर्भ है, इसलिए इसे self पर जाने के लिए निहित रूप से संदर्भित किया गया है, यही कारण है कि त्रुटि कहती है कि *map स्थानांतरित हो गया है।

एपीआई जानबूझकर इस तरह से बनाया गया है ताकि आप किसी संरचना पर लूपिंग करते समय खतरनाक कुछ भी नहीं कर सकें। एक बार लूप पूरा होने के बाद, संरचना का स्वामित्व समाप्त हो जाता है और आप इसे फिर से उपयोग कर सकते हैं।

fn do_it(map: &mut HashMap<String, String>) { 
    let mut to_remove = Vec::new(); 
    for (key, value) in &*map { 
     if key.starts_with("A") { 
      to_remove.push(key.to_owned()); 
     } 
    } 
    for key in to_remove.iter() { 
     map.remove(key); 
    } 
} 

तुम भी एक नया एक में नक्शा फिल्टर करने के लिए एक iterator उपयोग कर सकते हैं:

एक समाधान आइटम आप एक Vec में दूर करने के लिए करना चाहते हैं का ट्रैक रखने के लिए और फिर उन्हें बाद में निकालते हैं। इस तरह शायद कुछ:

fn do_it(map: &mut HashMap<String, String>) { 
    *map = map.into_iter().filter_map(|(key, value)| { 
     if key.starts_with("A") { 
      None 
     } else { 
      Some((key.to_owned(), value.to_owned())) 
     } 
    }).collect(); 
} 

लेकिन मैं सिर्फ Shepmaster के संपादन देखा - मैं retain के बारे में है, जो बेहतर है भूल गया था। यह अधिक संक्षिप्त है और जैसा मैंने किया है अनावश्यक प्रतिलिपि नहीं करता है।

संबंधित मुद्दे