Rust के `स्ट्रिंग` और` str` के बीच अंतर क्या हैं?


418

क्यों जंग है Stringऔर str? Stringऔर के बीच अंतर क्या हैं str? जब Stringइसके बजाय strऔर इसके विपरीत का उपयोग करता है ? क्या उनमें से एक पदावनत हो रहा है?

जवाबों:


488

Stringडायनामिक हीप स्ट्रिंग प्रकार है, जैसे Vec: इसका उपयोग तब करें जब आपको अपने स्ट्रिंग डेटा को स्वयं या संशोधित करने की आवश्यकता हो।

strस्मृति में कहीं कहीं गतिशील लंबाई के UTF-8 बाइट्स का एक अपरिवर्तनीय 1 अनुक्रम है। चूंकि आकार अज्ञात है, कोई केवल एक पॉइंटर के पीछे इसे संभाल सकता है। इसका मतलब यह है कि strआमतौर पर 2 के रूप में प्रकट होता है &str: कुछ यूटीएफ -8 डेटा का संदर्भ, जिसे आमतौर पर "स्ट्रिंग स्लाइस" या सिर्फ एक "स्लाइस" कहा जाता है। एक टुकड़ा केवल कुछ डेटा पर एक दृश्य है, और वह डेटा कहीं भी हो सकता है, जैसे

  • स्थिर भंडारण में : एक स्ट्रिंग शाब्दिक "foo"एक है &'static str। जब प्रोग्राम चलता है तो डेटा को निष्पादन योग्य में हार्डकोड किया जाता है और मेमोरी में लोड किया जाता है।
  • एक ढेर के अंदर आवंटित किया गयाString : डेटा के Stringएक &strदृश्य के लिए dereferencesString
  • स्टैक पर : उदाहरण के लिए, एक स्टैक-आबंटित बाइट सरणी बनाता है, और फिर उस के रूप में उस डेटा का&str एक दृश्य प्राप्त करता है :

    use std::str;
    
    let x: &[u8] = &[b'a', b'b', b'c'];
    let stack_str: &str = str::from_utf8(x).unwrap();
    

सारांश में, Stringयदि आपको स्वामित्व वाले स्ट्रिंग डेटा की आवश्यकता है (जैसे कि अन्य थ्रेड्स के लिए तार पास करना, या रनटाइम पर उनका निर्माण करना), और उपयोग करें &strयदि आपको केवल स्ट्रिंग के दृश्य की आवश्यकता है।

यह एक वेक्टर Vec<T>और एक स्लाइस &[T]के बीच संबंध के समान है, और सामान्य प्रकारों के लिए उप-मूल्य Tऔर उप-संदर्भ &Tके बीच संबंध के समान है ।


1strतय-लंबाई है; आप अंत से परे बाइट्स नहीं लिख सकते हैं, या अमान्य बाइट्स को पीछे छोड़ सकते हैं। चूंकि UTF-8 एक चर-चौड़ाई एन्कोडिंग है, यह प्रभावी रूप से सभी strको कई मामलों में अपरिवर्तनीय होने के लिए मजबूर करता है। सामान्य तौर पर, म्यूटेशन के लिए पहले की तुलना में अधिक या कम बाइट्स लिखने की आवश्यकता होती है (उदाहरण के लिए a(1 बाइट की जगह ) एक ä(2+ बाइट्स) के साथ अधिक कमरे बनाने की आवश्यकता होती है str। विशिष्ट तरीके हैं जो एक &strजगह को संशोधित कर सकते हैं , ज्यादातर वे जो केवल ASCII वर्णों को संभालते हैं, जैसे make_ascii_uppercase

2 डायनामिक आकार के प्रकारोंRc<str> को संदर्भ के एक क्रम के लिए अनुमति देते हैं जैसे कि रूस्ट 1.2 से यूटीएफ -8 बाइट्स गिना जाता है। जंग 1.21 आसानी से इन प्रकारों को बनाने की अनुमति देता है।


10
"UTF-8 बाइट्स का अनुक्रम ( अज्ञात लंबाई का )" - क्या यह पुराना है? डॉक्स कहते हैं कि "एक &strदो घटकों से बना है: कुछ बाइट्स के लिए सूचक है, और लंबाई।"
mcc

11
यह पुराना नहीं है (यह प्रतिनिधित्व काफी स्थिर रहा है), बस थोड़ा सा प्रभाव: यह सांख्यिकीय रूप से ज्ञात नहीं है, इसके विपरीत, कहते हैं [u8; N],।
हियोन

2
@ संकलन समय पर अज्ञात है, इसके आकार के बारे में धारणाएं नहीं बनाई जा सकती हैं, उदाहरण के लिए, स्टैक फ्रेम बनाते समय। इस प्रकार इसे अक्सर एक संदर्भ के रूप में माना जाता है, जो एक संदर्भ संकलन समय पर एक ज्ञात आकार है, जो एक सूचक का आकार है।
सेहत

1
अद्यतन: Rc<str>और Arc<str>अब मानक पुस्तकालय के माध्यम से उपयोग करने योग्य हैं।
सेंट्रिल

1
@cjohansson सांख्यिकीय रूप से आवंटित वस्तुओं को आम तौर पर न तो ढेर पर रखा जाता है, न ही स्टैक, बल्कि स्मृति के अपने क्षेत्र में।
ब्रेनन विंसेंट

96

मैं एक सी ++ पृष्ठभूमि है और मैं इसे बहुत के बारे में सोचना उपयोगी पाया Stringऔर &strसी ++ संदर्भ में:

  • एक जंग Stringकी तरह है std::string; यह स्मृति का मालिक है और स्मृति के प्रबंधन का गंदा काम करता है।
  • एक जंग &strकी तरह है char*(लेकिन थोड़ा और अधिक परिष्कृत); यह हमें उसी तरह से एक चंक की शुरुआत की ओर इशारा करता है जिस तरह से आप सामग्री की ओर संकेत कर सकते हैं std::string

क्या दोनों में से कोई गायब होने वाला है? मुझे ऐसा नहीं लगता है। वे दो उद्देश्यों की सेवा करते हैं:

Stringबफर रखता है और उपयोग करने के लिए बहुत व्यावहारिक है। &strहल्का है और इसे स्ट्रिंग्स में "देखने" के लिए उपयोग किया जाना चाहिए। आप नई मेमोरी को आवंटित करने की आवश्यकता के बिना खोज, विभाजन, पार्स और यहां तक ​​कि विखंडू को बदल सकते हैं।

&strअंदर देखने के Stringरूप में यह कुछ स्ट्रिंग शाब्दिक को इंगित कर सकता है। निम्नलिखित कोड को Stringप्रबंधित मेमोरी में शाब्दिक स्ट्रिंग को कॉपी करने की आवश्यकता है :

let a: String = "hello rust".into();

निम्नलिखित कोड आपको कॉपी के बिना ही शाब्दिक का उपयोग करने देता है (केवल हालांकि पढ़ें)

let a: &str = "hello rust";

12
एक string_view की तरह?
अभिनव गुनियाल

1
हाँ string_view की तरह लेकिन भाषा के लिए आंतरिक और ठीक से उधार लिया गया चेक।
लोका

41

str, केवल के रूप में इस्तेमाल किया &str, एक स्ट्रिंग टुकड़ा, एक UTF-8 बाइट सरणी के लिए एक संदर्भ है।

String~strयूटीएफ -8 बाइट सरणी के रूप में , एक बढ़ने योग्य, स्वामित्व वाला है।


तकनीकी रूप से, जो ~strअब हुआ करता थाBox<str>
jv110

3
@ jv110: नहीं, क्योंकि ~strबढ़ने योग्य था जबकि बढ़ने Box<str>योग्य नहीं है। (यह ~strऔर ~[T]जादुई उगने वाली दाढ़ी थे किसी अन्य के विपरीत ~-object, वास्तव में था क्यों Stringऔर Vec<T>शुरू किए गए थे, ताकि नियम सभी सीधा और निरंतर चल रहे थे।)
क्रिस मॉर्गन

18

वे वास्तव में पूरी तरह से अलग हैं। सबसे पहले, strयह एक प्रकार की चीज़ के अलावा कुछ नहीं है; यह केवल प्रकार के स्तर के बारे में तर्क दिया जा सकता है क्योंकि यह एक तथाकथित गतिशील रूप से आकार प्रकार (DST) है। आकार strलेता है संकलन समय पर नहीं जाना जा सकता है और रनटाइम जानकारी पर निर्भर करता है - इसे एक चर में संग्रहीत नहीं किया जा सकता है क्योंकि संकलक को संकलन समय पर यह जानना होगा कि प्रत्येक चर का आकार क्या है। A strवैचारिक रूप u8से गारंटी के साथ बाइट्स की एक पंक्ति है जो वैध UTF-8 बनाता है। पंक्ति कितनी बड़ी है? कोई भी रनटाइम तक नहीं जानता है इसलिए इसे एक चर में संग्रहीत नहीं किया जा सकता है।

दिलचस्प बात यह है कि एक है &strएक करने के लिए या किसी अन्य सूचक strकी तरह Box<str> करता है क्रम पर मौजूद हैं। यह एक तथाकथित "वसा सूचक" है; यह अतिरिक्त जानकारी के साथ एक संकेतक है (इस मामले में उस चीज़ का आकार जो इसे इंगित कर रहा है) इसलिए यह दोगुना बड़ा है। वास्तव में, यह &strएक String(लेकिन नहीं &String) के काफी करीब है । ए &strदो शब्द है; पहले बाइट की एक पॉइंटर strऔर दूसरी संख्या जो बताती है कि यह कितने बाइट्स strहै।

जो कहा गया है, उसके विपरीत, strअपरिवर्तनीय होने की आवश्यकता नहीं है। यदि आप के लिए एक &mut strविशेष सूचक के रूप में प्राप्त कर सकते हैं str, तो आप इसे और सभी सुरक्षित कार्यों को म्यूट कर सकते हैं जो गारंटी देते हैं कि UTF-8 बाधा को बरकरार रखा जाता है क्योंकि यदि इसका उल्लंघन किया जाता है तो हमारे पास अपरिभाषित व्यवहार होता है क्योंकि पुस्तकालय इस बाधा को मानता है। सच है और इसके लिए जाँच नहीं करता है।

तो एक क्या है String? वह तीन शब्द हैं; दो इसके लिए समान हैं, &strलेकिन यह एक तीसरा शब्द जोड़ता है जो strकि ढेर पर बफर की क्षमता है , हमेशा ढेर पर ( strयह जरूरी नहीं है कि यह ढेर पर हो) इससे पहले कि यह भर जाता है और इसे फिर से आवंटित करना पड़ता है। Stringमूल रूप से मालिक एक strके रूप में वे कहते हैं; यह इसे नियंत्रित करता है और इसे आकार बदल सकता है और इसे तब फिट कर सकता है जब यह फिट दिखता है। तो एक Stringके रूप में कहा जाता है कि एक &strसे एक के करीब है str

एक और बात है Box<str>; यह भी एक मालिक है strऔर इसका रनटाइम प्रतिनिधित्व समान है, &strलेकिन यह इसके strविपरीत का भी मालिक है , &strलेकिन यह इसे आकार नहीं दे सकता है क्योंकि यह इसकी क्षमता को नहीं जानता है इसलिए मूल Box<str>रूप से एक निश्चित-लंबाई के रूप में देखा जा सकता है Stringजिसे आकार नहीं दिया जा सकता है (आप कर सकते हैं Stringयदि आप इसे आकार बदलना चाहते हैं तो हमेशा इसे रूपांतरित करें )।

एक समान समान संबंध मौजूद है [T]और Vec<T>इसके अलावा कोई UTF-8 बाधा नहीं है और यह किसी भी प्रकार को पकड़ सकता है जिसका आकार गतिशील नहीं है।

के उपयोग strपर प्रकार के स्तर के साथ सामान्य कपोल-कल्पना बनाने के लिए ज्यादातर है &str; यह आसानी से लक्षण लिखने में सक्षम होने के लिए प्रकार के स्तर पर मौजूद है। सिद्धांत strरूप में एक प्रकार की चीज का अस्तित्व होना आवश्यक नहीं था और केवल &strइसका मतलब है कि बहुत सारे अतिरिक्त कोड लिखने होंगे जो अब सामान्य हो सकते हैं।

&strसुपर उपयोगी Stringहै कॉपी करने के लिए एक के बिना कई अलग अलग substrates है करने में सक्षम होने के लिए; के रूप में एक ने कहा कि String मालिकstr ढेर यह प्रबंधन करता है पर और यदि आप केवल एक की सबस्ट्रिंग बना सकते हैं Stringएक नए के साथ Stringकॉपी क्योंकि जंग में सब कुछ केवल स्मृति सुरक्षा से निपटने के लिए एक ही स्वामी हो सकता करने के लिए होगा। तो उदाहरण के लिए आप एक स्ट्रिंग टुकड़ा कर सकते हैं:

let string: String   = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];

हमारे पास strएक ही स्ट्रिंग के दो अलग-अलग विकल्प हैं । stringवह है जो strहीप पर वास्तविक पूर्ण बफर का मालिक है और &strसबस्ट्रिंग ढेर पर उस बफर के लिए केवल वसा संकेत हैं।


4

std::Stringबस का एक वेक्टर है u8। आप इसकी परिभाषा स्रोत कोड में पा सकते हैं । यह ढेर-आवंटित और बढ़ने योग्य है।

#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
    vec: Vec<u8>,
}

strएक आदिम प्रकार है, जिसे स्ट्रिंग स्लाइस भी कहा जाता है । एक स्ट्रिंग टुकड़ा का निश्चित आकार है। एक शाब्दिक स्ट्रिंग की तरह let test = "hello world"है &'static strtestइस सांख्यिकीय रूप से आवंटित स्ट्रिंग का एक संदर्भ है। &strउदाहरण के लिए, संशोधित नहीं किया जा सकता

let mut word = "hello world";
word[0] = 's';
word.push('\n');

str&mut strउदाहरण के लिए परस्पर स्लाइस है : pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)

let mut s = "Per Martin-Löf".to_string();
{
    let (first, last) = s.split_at_mut(3);
    first.make_ascii_uppercase();
    assert_eq!("PER", first);
    assert_eq!(" Martin-Löf", last);
}
assert_eq!("PER Martin-Löf", s);

लेकिन UTF-8 में एक छोटा सा बदलाव इसकी बाइट की लंबाई को बदल सकता है, और एक स्लाइस इसके संदर्भ को पुनः प्राप्त नहीं कर सकता है।


0

आसान शब्दों में, Stringडीटाइपाइप को ढेर (जैसे Vec) पर संग्रहीत किया जाता है , और आपके पास उस स्थान तक पहुंच होती है।

&strएक स्लाइस प्रकार है। इसका मतलब है कि यह सिर्फ एक पहले से ही Stringकहीं मौजूद ढेर का संदर्भ है ।

&strरनटाइम पर कोई आवंटन नहीं करता है। तो, स्मृति कारणों के लिए, आप &strपर उपयोग कर सकते हैं String। लेकिन, इस बात का ध्यान रखें कि उपयोग करते समय &strआपको स्पष्ट जीवनकाल से निपटना पड़ सकता है।


1
ढेर में कहीं - यह पूरी तरह से सही नहीं है।
शेमपस्टर

मेरा मतलब था कि strवह viewपहले से ही Stringढेर में मौजूद है।
00imvj00

1
मैं समझता हूं कि आपका मतलब क्या है, और मैं कह रहा हूं कि यह पूरी तरह से सही नहीं है। "हीप" बयान का एक आवश्यक हिस्सा नहीं है।
श्पेमास्टर

-1

C # और Java लोगों के लिए:

  • जंग ' String===StringBuilder
  • जंग का &str === (अपरिवर्तनीय) तार

मैं &strएक स्ट्रिंग पर एक दृश्य के रूप में सोचना पसंद करता हूं , जैसे जावा / सी # में एक प्रशिक्षु स्ट्रिंग जहां आप इसे बदल नहीं सकते हैं, केवल एक नया बना सकते हैं।


1
Java / C # स्ट्रिंग्स और रस्ट स्ट्रिंग्स के बीच सबसे बड़ा अंतर यह है कि Rust guarentees स्ट्रिंग को सही यूनिकोड करता है, जैसे कि एक स्ट्रिंग में तीसरा कंट्रोलर प्राप्त करने के लिए केवल "abc" [2] से अधिक विचार की आवश्यकता होती है। (यह देखते हुए कि हम एक बहुभाषी दुनिया में रहते हैं, यह एक अच्छी बात है।)
गिलहरी

यह गलत है । शीर्ष-मतदान जवाब में उत्परिवर्तन का विषय पहले से ही संबोधित है; अधिक जानने के लिए कृपया इसे पढ़ें।
12pm पर Shepmaster

-5

यहाँ एक त्वरित और आसान स्पष्टीकरण है।

String- एक बढ़ने योग्य, हीबल हीप-आवंटित डेटा संरचना। यह एक करने के लिए मजबूर किया जा सकता है &str

str- (अब, जैसा कि जंग विकसित होती है) उत्परिवर्तित, निश्चित-लंबाई वाली स्ट्रिंग है जो ढेर पर या बाइनरी में रहती है। आप केवल strएक स्ट्रिंग स्लाइस दृश्य के माध्यम से उधार के प्रकार के साथ बातचीत कर सकते हैं , जैसे कि &str

उपयोग के विचार:

पसंद करें Stringयदि आप किसी स्ट्रिंग को स्वयं करना या म्यूट करना चाहते हैं - जैसे कि स्ट्रिंग को किसी अन्य थ्रेड को पास करना, आदि।

&strयदि आप किसी स्ट्रिंग का केवल पढ़ने के लिए दृश्य चाहते हैं, तो उसे प्राथमिकता दें।


यह गलत है । शीर्ष-मतदान जवाब में उत्परिवर्तन का विषय पहले से ही संबोधित है; अधिक जानने के लिए कृपया इसे पढ़ें।
12pm पर Shepmaster
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.