স্ট্রিং (& স্ট্রিং), ভেক (এবং ভেক), বা বাক্স (এবং বাক্স) এর কোনও ফাংশন আর্গুমেন্ট হিসাবে কোনও রেফারেন্স গ্রহণ করতে কেন নিরুৎসাহিত করা হচ্ছে?


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এবং তারপরে শেষ হওয়ার জন্য দ্বিতীয় সীমাবদ্ধতা সম্পাদন করতে হবে &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 পয়েন্টটি প্রায়শই আমার মনে হয় এমন গুরুত্বপূর্ণ হয় না। সাধারণত Vecএস এবং Stringএস স্ট্যাকের উপরে এবং প্রায়শই কোথাও কোথাও বর্তমান স্ট্যাক ফ্রেমের কাছাকাছি বাস করবে। স্ট্যাকটি সাধারণত উষ্ণ থাকে এবং সিপিইউ ক্যাশে থেকে ডিসেরফারেন্স পরিবেশিত হবে।
লুকাশ কালবার্টডট

3
@ শিপমাস্টার: বরাদ্দ ব্যয়ের বিষয়ে, বাধ্যতামূলক বরাদ্দের বিষয়ে কথা বলার সময় সাবস্ট্রিং / স্লাইসগুলির নির্দিষ্ট ইস্যুটি উল্লেখ করা উচিত। total_price(&prices[0..4])স্লাইসের জন্য কোনও নতুন ভেক্টর বরাদ্দ করার প্রয়োজন নেই।
ম্যাথিউ এম।

4
এটি একটি দুর্দান্ত উত্তর। আমি কেবল মরিচায় শুরু করছি এবং কখন একটি ব্যবহার করব &strএবং কেন (পাইথন থেকে আসছি, তাই আমি সাধারণত প্রকারের সাথে সুস্পষ্টভাবে আচরণ করি না) তা নির্ধারণ করতে গিয়েছিলাম।
এগুলি

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]>ইত্যাদির সাথেও কাজ করবে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.