फ़ंक्शन के तर्क के रूप में स्ट्रिंग (& String), Vec (& Vec) या बॉक्स (& Box) के संदर्भ को स्वीकार करने के लिए इसे हतोत्साहित क्यों किया जाता है?


127

मैंने कुछ रस्ट कोड लिखे जो &Stringएक तर्क के रूप में लेता है :

fn awesome_greeting(name: &String) {
    println!("Wow, you are awesome, {}!", name);
}

मैं भी लिखा है कोड है कि एक के लिए एक संदर्भ में लेता है Vecया Box:

fn total_price(prices: &Vec<i32>) -> i32 {
    prices.iter().sum()
}

fn is_even(value: &Box<i32>) -> bool {
    **value % 2 == 0
}

हालाँकि, मुझे कुछ प्रतिक्रिया मिली कि ऐसा करना अच्छा विचार नहीं है। क्यों नहीं?

जवाबों:


162

टीएल; डीआर: एक का उपयोग कर सकते हैं &str, &[T]या &Tअधिक सामान्य कोड के लिए अनुमति देने के लिए।


  1. एक Stringया एक Vecका उपयोग करने के मुख्य कारणों में से एक है क्योंकि वे क्षमता बढ़ाने या कम करने की अनुमति देते हैं। हालांकि, जब आप एक अपरिवर्तनीय संदर्भ स्वीकार करते हैं, आप पर उन दिलचस्प तरीकों में से किसी का उपयोग नहीं कर सकते हैं Vecया String

  2. एक स्वीकारना &String, &Vecया &Boxभी आवश्यकता तर्क ढेर पर आवंटित किया इससे पहले कि आप समारोह कॉल कर सकते हैं। एक स्वीकारना &strकी अनुमति देता है एक स्ट्रिंग शाब्दिक (कार्यक्रम डेटा में बचाया) और एक को स्वीकार करने &[T]या &Tएक ढेर-आवंटित सरणी या चर अनुमति देता है। अनावश्यक आवंटन एक प्रदर्शन हानि है। जब आप इन विधियों को परीक्षण या किसी mainविधि में कॉल करने का प्रयास करते हैं, तो यह आमतौर पर तुरंत सामने आ जाता है :

    awesome_greeting(&String::from("Anna"));
    total_price(&vec![42, 13, 1337])
    is_even(&Box::new(42))
  3. एक और प्रदर्शन पर विचार है &String, &Vecऔर &Boxअप्रत्यक्ष रूप से एक अनावश्यक परत का परिचय के रूप में आप &Stringएक पाने के लिए Stringऔर फिर अंत में खत्म करने के लिए एक दूसरे dereference प्रदर्शन है &str

इसके बजाय, आपको एक स्ट्रिंग स्लाइस ( &str), एक स्लाइस ( &[T]), या सिर्फ एक संदर्भ ( &T) स्वीकार करना चाहिए । एक &String, &Vec<T>या &Box<T>स्वचालित रूप से एक करने के लिए मजबूर हो जाएगा &str, &[T]या &Tक्रमशः।

fn awesome_greeting(name: &str) {
    println!("Wow, you are awesome, {}!", name);
}
fn total_price(prices: &[i32]) -> i32 {
    prices.iter().sum()
}
fn is_even(value: &i32) -> bool {
    *value % 2 == 0
}

अब आप इन तरीकों को व्यापक प्रकार के सेट के साथ कह सकते हैं। उदाहरण के लिए, awesome_greetingएक स्ट्रिंग शाब्दिक ( "Anna") या आवंटित के साथ कहा जा सकता है Stringtotal_priceएक सरणी ( &[1, 2, 3]) या आवंटित के संदर्भ के साथ बुलाया जा सकता है Vec


आप जोड़ सकते हैं या से आइटम निकाल करना चाहते हैं तो Stringया Vec<T>, आप एक समय लग सकता है परिवर्तनशील संदर्भ ( &mut Stringया &mut Vec<T>):

fn add_greeting_target(greeting: &mut String) {
    greeting.push_str("world!");
}
fn add_candy_prices(prices: &mut Vec<i32>) {
    prices.push(5);
    prices.push(25);
}

विशेष रूप से स्लाइस के लिए, आप भी स्वीकार कर सकते हैं &mut [T]या &mut str। यह आपको स्लाइस के अंदर एक विशिष्ट मूल्य को बदलने की अनुमति देता है, लेकिन आप स्लाइस के अंदर वस्तुओं की संख्या को बदल नहीं सकते हैं (जिसका अर्थ है कि यह स्ट्रिंग्स के लिए बहुत प्रतिबंधित है):

fn reset_first_price(prices: &mut [i32]) {
    prices[0] = 0;
}
fn lowercase_first_ascii_character(s: &mut str) {
    if let Some(f) = s.get_mut(0..1) {
        f.make_ascii_lowercase();
    }
}

5
शुरुआत में डॉ। टीएल के बारे में कैसे ? यह उत्तर पहले से ही कुछ लंबा है। कुछ ऐसा है " &strकम क्षमताओं के बिना (जैसे: में कम प्रतिबंध लगाता है) अधिक सामान्य है"? भी: बिंदु 3 अक्सर महत्वपूर्ण नहीं है जो मुझे लगता है। आमतौर पर Vecs और Strings स्टैक पर रहते हैं और अक्सर कहीं न कहीं वर्तमान स्टैक फ्रेम के पास भी होते हैं। स्टैक आमतौर पर गर्म होता है और एक सीपीयू कैश से डीरेफेरेंस परोसा जाएगा।
लुकास कालबर्टोड

3
@ शेमेस्टर: आवंटन लागत के बारे में, यह अनिवार्य आवंटन के बारे में बात करते समय सबस्ट्रिंग / स्लाइस के विशेष मुद्दे का उल्लेख करने के लायक हो सकता है। total_price(&prices[0..4])स्लाइस के लिए एक नया वेक्टर आवंटित करने की आवश्यकता नहीं है।
मैथ्यू एम।

4
यह एक बेहतरीन जवाब है। मैं बस जंग में शुरू हो रहा हूं और यह पता लगा रहा हूं कि मुझे कब &strऔर क्यों इस्तेमाल करना चाहिए (पायथन से आ रहा है, इसलिए मैं आमतौर पर प्रकारों के साथ सौदा नहीं करता हूं)। सभी को पूरी तरह से साफ़ कर दिया
C.Nivs

2
मापदंडों पर भयानक सुझाव। बस एक संदेह की आवश्यकता है: "एक & स्ट्रिंग, और वीईसी या & बॉक्स को स्वीकार करने से पहले आपको विधि को कॉल करने के लिए एक आवंटन की आवश्यकता होती है।" ... ऐसा क्यों है? क्या आप डॉक्स में वह हिस्सा बता सकते हैं जहां मैं इसे विस्तार से पढ़ सकता हूं? (मैं एक भिखारी हूं)। इसके अलावा, क्या हम वापसी के प्रकारों पर समान सुझाव दे सकते हैं?
नवाज

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

22

शमपास्टर के उत्तर के अलावा , &str(और इसी तरह &[T]आदि) को स्वीकार करने का एक और कारण इसके अलावा String और सभी प्रकारों से &strसंतुष्ट है Deref<Target = str>। सबसे उल्लेखनीय उदाहरणों में से एक हैCow<str> , जो आपको इस बारे में बहुत लचीला बनाता है कि क्या आप स्वामित्व या उधार डेटा के साथ काम कर रहे हैं।

यदि आपके पास है:

fn awesome_greeting(name: &String) {
    println!("Wow, you are awesome, {}!", name);
}

लेकिन आपको इसे एक के साथ कॉल करने की आवश्यकता है Cow<str>, आपको यह करना होगा:

let c: Cow<str> = Cow::from("hello");
// Allocate an owned String from a str reference and then makes a reference to it anyway!
awesome_greeting(&c.to_string());

जब आप तर्क प्रकार को बदलते हैं &str, तो आप Cowबिना किसी अनावश्यक आवंटन के, बिना किसी अनावश्यक आवंटन का उपयोग कर सकते हैं , जैसे String:

let c: Cow<str> = Cow::from("hello");
// Just pass the same reference along
awesome_greeting(&c);

let c: Cow<str> = Cow::from(String::from("hello"));
// Pass a reference to the owned string that you already have
awesome_greeting(&c);

स्वीकार करना &strआपके फ़ंक्शन को अधिक समान और सुविधाजनक बनाता है, और "सबसे आसान" तरीका अब भी सबसे कुशल है। ये उदाहरण Cow<[T]>आदि के साथ भी काम करेंगे ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.