मेरे पास निम्न कोड है:

#![allow(unused)]
#![allow(unused_must_use)]
use std::collections::HashMap;

#[derive(Clone, Debug)]
struct Product {
    name: String,
    description: Option<String>,
    barcode: String,
    price: String
}


fn main() {

   println!("Loading product list");

   let mut h: HashMap<&str, Vec<Product>> = HashMap::new();
 
   let plastic_bag = Product{ name: "Plastic Bag".to_string(), description: None, barcode: "0001A".to_string(), price: "4.50".to_string() };
   let recyclable_bag = Product{ name: "Recyclable Bag".to_string(), description: None, barcode: "0001B".to_string(), price: "15.50".to_string() };
   
   let category = vec![recyclable_bag, plastic_bag];
   
   h.insert("checkout", category);
   
   println!("{:#?}", h);
   
   let mut h = make_free("checkout", &h);
   
   println!("{:#?}", h);
}

fn make_free<'a>(category: &'a str, checkout_category: &'a mut HashMap<&str, Vec<Product>>) -> &'a mut HashMap<&'a str, Vec<Product>> {
    
    let mut category = checkout_category.get_mut(category).unwrap();
    
    for product in  category {
       product.price = "0.00".to_string();
       println!("{:#?}", product);
   }
   
   return checkout_category
    
}

मेरे पास पहले से परिभाषित उत्पादों की एक सूची है। मेरे पास एक विधि है जिसे मैं कहता हूं कि मैं उधार संदर्भ की सामग्री की कीमतों को $0 में बदलना चाहता हूं।

मुझे 2 त्रुटियां मिलती हैं:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:31:38
   |
31 |    let mut h = make_free("checkout", &h);
   |                                      ^^ types differ in mutability
   |
   = note: expected mutable reference `&mut std::collections::HashMap<&str, std::vec::Vec<Product>>`
                      found reference `&std::collections::HashMap<&str, std::vec::Vec<Product>>`

error[E0621]: explicit lifetime required in the type of `checkout_category`
  --> src/main.rs:45:11
   |
36 | fn make_free<'a>(category: &'a str, checkout_category: &'a mut HashMap<&str, Vec<Product>>) -> &'a mut HashMap<&'a str, Vec<Product>> {
   |                                                        ----------------------------------- help: add explicit lifetime `'a` to the type of `checkout_category`: `&'a mut std::collections::HashMap<&'a str, std::vec::Vec<Product>>`
...
45 |    return checkout_category
   |           ^^^^^^^^^^^^^^^^^ lifetime `'a` required

मैं वास्तव में उलझन में हूं कि आप रिटर्न स्टेटमेंट में आजीवन विनिर्देशक कैसे जोड़ सकते हैं, और प्रकार अलग क्यों हैं।

1
Tarang 25 अगस्त 2020, 09:43

2 जवाब

सबसे बढ़िया उत्तर

इस कोड के साथ कई समस्याएं हैं और वे सभी रस्ट की स्वामित्व की अवधारणा और साझा और परस्पर संदर्भों से संबंधित हैं। मैं मुफ़्त के स्वामित्व को समझना अनुभाग पढ़ने का सुझाव देता हूं द रस्ट प्रोग्रामिंग लैंग्वेज बुक या इससे भी बेहतर "प्रोग्रामिंग" में संबंधित अनुभाग जंग" ओ'रेली से।

संक्षेप में, स्वामित्व के संबंध में सबसे महत्वपूर्ण नियम इस प्रकार हैं:

  1. मूल्यों का एक ही स्वामी होता है। एक नए चर के लिए एक मूल्य को फिर से निर्दिष्ट करना मूल्य को स्थानांतरित करता है और व्यापक रूप से स्वामित्व वाले चर को अमान्य/अनुपयोगी बनाता है। जंग इसे संकलन समय पर ट्रैक करता है। जब वेरिएबल जो किसी मान का स्वामी होता है, वह दायरे से बाहर हो जाता है तो मान गिरा दिया जाता है (= हटा दिया जाता है)।

  2. एक मान के कई साझा संदर्भ (जैसे &HashMap<..>) हो सकते हैं। जब एक या अधिक साझा संदर्भ होते हैं, तो मान अपरिवर्तनीय होता है।

  3. वैकल्पिक रूप से, एक मान का एक (और केवल एक) परिवर्तनशील संदर्भ (जैसे &mut HashMap<..>) हो सकता है। जब एक परिवर्तनीय संदर्भ मौजूद होता है तो कोई अन्य संदर्भ (साझा या परिवर्तनीय) मौजूद नहीं हो सकता है। परिवर्तनीय संदर्भ अद्वितीय हैं।

  4. सन्दर्भों को कभी भी उस मूल्य से आगे नहीं बढ़ना चाहिए जिसका वे उल्लेख करते हैं।

(इन नियमों को मोड़ने के तरीके हैं, लेकिन ये रस्ट में मूल नियम हैं और समझने के लिए महत्वपूर्ण हैं।)

रस्ट में भ्रमित करने वाला दूसरा भाग String और &str के बीच का अंतर है। फिर से, मैं इस पर और अधिक पढ़ने की सलाह देता हूं, लेकिन सार है

  • String ढेर पर एक स्ट्रिंग मान का स्वामी है
  • &str उस स्ट्रिंग का संदर्भ है जो किसी और के पास है।

अब, कोड को देख रहे हैं

let mut h: HashMap<&str, Vec<Product>> = HashMap::new();

यह हिस्सा थोड़ा अजीब है (यह वही हो सकता है जो आप चाहते थे, लेकिन शायद नहीं): चर h के पास HashMap है, लेकिन HashMap के पास इसकी चाबियां नहीं हैं, यह केवल उनके संदर्भ हैं। प्रति नियम (4) h किसी भी कुंजी से अधिक समय तक नहीं रहना चाहिए। व्यवहार में, रस्ट इसे ट्रैक नहीं कर सकता है, इसलिए यह हैशमैप प्रभावी रूप से &str संदर्भों को रखने तक सीमित है जो पूरे कार्यक्रम के लिए रहते हैं, इन्हें &'static str कहा जाता है, सबसे आम स्ट्रिंग अक्षर हैं।

एक HashMap प्राप्त करने के लिए जो अपनी चाबियों का मालिक है (वे सामान्य मामले में), आप उपयोग करेंगे

let mut h: HashMap<String, Vec<Product>> = HashMap::new();
//                 ^^^^^^-- instead of &str

अब make_free फ़ंक्शन प्राप्त होने वाले हैशमैप को संशोधित करना चाहता है। ऐसा करने के दो मुहावरेदार तरीके हैं: (ए) हैशमैप का स्वामित्व लें और एक नया हैशमैप लौटाएं या (बी) एक परिवर्तनीय संदर्भ लें &mut HashMap<..> और इसे जगह में संशोधित करें लेकिन कुछ भी वापस न करें। इस मामले में एक परिवर्तनीय संदर्भ का उपयोग करना अधिक स्वाभाविक होगा:

fn make_free(category: &str, checkout_category: &mut HashMap<String, Vec<Product>>) {
    
    let mut category = checkout_category.get_mut(category).unwrap();
    
    for product in  category {
       product.price = "0.00".to_string();
       println!("{:#?}", product);
   }
    

ध्यान दें कि आपको इस मामले में जीवनकाल की आवश्यकता नहीं है, आपको केवल उनकी आवश्यकता है जब आप कोई संदर्भ लौटाते हैं (जो दुर्लभ है)।

हैशमैप के स्वामित्व वाले String और make_free के इस संस्करण का उपयोग करके कोड बन जाता है (खेल का मैदान लिंक):

#![allow(unused)]
#![allow(unused_must_use)]
use std::collections::HashMap;

#[derive(Clone, Debug)]
struct Product {
    name: String,
    description: Option<String>,
    barcode: String,
    price: String
}


fn main() {
   println!("Loading product list");
   let mut h: HashMap<String, Vec<Product>> = HashMap::new();

   let plastic_bag = Product{ name: "Plastic Bag".to_string(), description: None, barcode: "0001A".to_string(), price: "4.50".to_string() };
   let recyclable_bag = Product{ name: "Recyclable Bag".to_string(), description: None, barcode: "0001B".to_string(), price: "15.50".to_string() };

   let category = vec![recyclable_bag, plastic_bag];
   h.insert("checkout".to_string(), category);
 
   println!("{:#?}", h);
   
   make_free("checkout", &mut h);
   
   println!("{:#?}", h);
}

fn make_free(category: &str, checkout_category: &mut HashMap<String, Vec<Product>>) {
    let mut category = checkout_category.get_mut(category).unwrap();
    
    for product in  category {
       product.price = "0.00".to_string();
       println!("{:#?}", product);
   }
 }

3
Paul 25 अगस्त 2020, 10:26

स्वामित्व और आजीवन समस्याएं एक तरफ, आपका मुख्य मुद्दा यह है कि इनपुट पैरामीटर में पहले प्रकार के तर्क पर जीवनकाल गुम है: आपके पास HashMap<&'a str, Vec<Product>> के बजाय HashMap<&str, Vec<Product>> है जो रिटर्न प्रकार है। इसलिए checkout_category का अनुमानित जीवनकाल 'a नहीं है, जो विधि हस्ताक्षर द्वारा आवश्यक है। लापता 'a को जोड़ने से यह ठीक हो जाता है।

इसके बाद, आपका फ़ंक्शन make_free एक &mut संदर्भ लेता है लेकिन आपने h को & संदर्भ के रूप में उधार लिया है। यह आसानी से तय हो जाता है:

let mut h = make_free("checkout", &mut h);
1
Lytigas 26 अगस्त 2020, 04:59