2017-12-13 103 views
5

मैं एक समारोह है कि निम्न करेगा बनाने के लिए कोशिश कर रहा हूँ उल्टा करने के लिए:
इनपुट: प्रपत्र "abc/डीईएफ़/GHI"
के मनमाने ढंग से लंबाई के एक String आउटपुट:String जहां "/" से अलग सभी सबस्ट्रिंग उलट दिए जाते हैं; इस उदाहरण में, आउटपुट "सीबीए/फेड/आईएचजी" होगा।जंग में कैसे उत्परिवर्तित को इटरेटर तत्वों सबस्ट्रिंग

फ़ंक्शन से अधिक, मुझे split() फ़ंक्शन द्वारा उत्पन्न एक पुनरावर्तक को उत्परिवर्तित करने के पीछे सामान्य सिद्धांत की परवाह है।

fn reverse_string(input: &mut str) -> String { 
    input 
     .to_string() 
     .split('/') 
     .map(move |x| x.to_string().rev()) 
     .collect::<String>() 
} 

संकलक शिकायत है कि

error[E0599]: no method named `rev` found for type `std::string::String` in the current scope 
--> src/main.rs:5:37 
    | 
5 |   .map(move |x| x.to_string().rev()) 
    |          ^^^ 
    | 
    = note: the method `rev` exists but the following trait bounds were not satisfied: 
      `&mut std::string::String : std::iter::Iterator` 
      `&mut str : std::iter::Iterator` 

क्या मतलब है और कैसे मैं इस समस्या को हल कर सकते हैं करता है:

नीचे अपना सर्वश्रेष्ठ प्रयास है?

+0

अपनी फ़ाइल के शीर्ष पर 'std :: iter :: Iterator;' का उपयोग करें। 'Iterator' विधि में परिभाषित 'rev' विधि का उपयोग करने के दायरे में होना आवश्यक है। – EvilTak

+1

@EvilTak 'Iterator' प्रस्ताव में है, इसलिए आपको इसे कभी भी उपयोग नहीं करना पड़ेगा। त्रुटि संदेश स्पष्ट रूप से कहता है कि विशेषता सीमाएं संतुष्ट नहीं हैं। "निम्नलिखित विशेषता लागू की गई है लेकिन दायरे में नहीं है" एक अलग संदेश है। – trentcl

+0

@trentcl आह, त्रुटि को गलत तरीके से पढ़ें। "निम्नलिखित विशेषता ..." पढ़ें और तत्काल एक आउट-ऑफ-स्कोप त्रुटि मान ली गई :) – EvilTak

उत्तर

4

यदि आप इसे इटरेटर्स सीख रहे हैं, तो मैं पहले का निर्णय लेने का सुझाव देता हूं कि आप वास्तव में ऐसा करने से पहले क्या करना चाहते हैं।

उदाहरण के लिए, यहाँ एक भी स्मृति आवंटन के साथ एक उदाहरण है:

fn reverse_string(input: &str) -> String { 
    let mut result = String::with_capacity(input.len()); 

    for portion in input.split('/') { 
     if !result.is_empty() { 
      result.push('/'); 
     } 
     for c in portion.chars().rev() { 
      result.push(c); 
     } 
    } 

    result 
} 

Iterators आम तौर पर शुद्ध तरीकों जो अपने वातावरण को संशोधित नहीं पर ध्यान केंद्रित कर रहे हैं। दुर्भाग्यवश, इससे यहां अक्षमता हो सकती है क्योंकि यह String को बाएं और दाएं बनाने और छोड़ने का संकेत देगी।

अब, तकनीकी रूप से आप पर्यावरण map में उत्परिवर्तित कर सकते हैं (यह एक FnMut लेता है), यह सिर्फ पर सिकोड़ी है क्योंकि प्रथा के अनुसार पाठकों यह शुद्ध होने की उम्मीद।

एक परिणाम है, जब आप, में अतिरिक्त राज्य लाने के लिए Iterator::fold चाहते के रूप में जाने के लिए विधि है:

fn reverse_string(input: &str) -> String { 
    input 
     .split('/') 
     .fold(
      String::with_capacity(input.len()), 
      |mut acc, portion| { 
       if !acc.is_empty() { 
        acc.push('/'); 
       } 
       for c in portion.chars().rev() { 
        acc.push(c); 
       } 
       acc 
      } 
     ) 
} 

पहला तर्क एक संचायक, जो बंद होने की प्रत्येक मंगलाचरण, को पारित कर दिया है, जो फिर इसे वापस करें। अंत में, fold कॉल के अंत में, जमाकर्ता फिर वापस कर दिया जाता है।

यह तर्क और दक्षता दोनों के मामले में पहले कार्य के बराबर है, लेकिन ईमानदारी से मैं for संस्करण ईमानदार होने के लिए पसंद करता हूं।

+0

नोट्स: (1) मुझे 'Iterator ' को' स्ट्रिंग' 'में जोड़ने का कोई तरीका नहीं मिला है और (2) मुझे आश्चर्य है कि कोई तरीका है या नहीं 'Iterator' के 'इटरेटर' उत्पन्न करने के लिए और उसके बाद 'flat_join' कॉल या कुछ के साथ नरक को फ़्लैट करें। –

3

यहाँ मेरी प्रयास है:

fn reverse_string(input: &mut str) -> String { 
    input.split('/') // split the input string by '/' 
     .map(|x| x.chars().rev().collect::<String>()) // reverse the sections and collect them 
     .collect::<Vec<String>>() // collect the reversed sections into a vector of Strings 
     .join("/") // join the strings so they are connected by '/' again 
} 

fn main() { 
    let mut s = String::from("abc/def/ghi"); 

    println!("{}", reverse_string(&mut s)); // cba/fed/ihg 
} 

अपने कोड में मुख्य त्रुटि है कि आप एक String पुनरावृति करने की कोशिश की थी, लेकिन यह Iterator को लागू नहीं करता है; इसे इसके .chars() या .bytes() पर फिर से चालू करने की आवश्यकता है।

+0

इस त्वरित उत्तर के लिए बहुत बहुत धन्यवाद! त्रुटि संदेश को बेहतर ढंग से समझने के लिए, 'std :: string :: स्ट्रिंग: std :: iter :: Iterator' मुझे बता रहा है कि स्ट्रिंग विशेषता को लागू नहीं करती है, मुझे अब यह मिलता है। दूसरी पंक्ति क्या है, 'str: std :: iter :: Iterator' का मतलब है? क्या यह सिर्फ उस फ़ाइल का संदर्भ है जहां संशोधित विधि परिभाषित की गई है? – SquattingSlavInTracksuit

+0

'संग्रह :: >' के दौरान 'Vec' के निर्माण से बचने का कोई तरीका है? (यानी अस्थायी वैक्टर के बिना शामिल हो रहे हैं) –

+2

@ स्ट्रिंगिंगस्लावइनट्रैकिट 'स्ट्रिंग' लागू करता है 'डेफ ', यह 'str' के सभी तरीकों को प्राप्त करता है। त्रुटि इंगित करती है कि न तो 'स्ट्रिंग' और न ही 'स्ट्र' से प्राप्त विधियों को इसे 'इटरेटर' की तरह माना जा सकता है। – ljedrz

3

.chars() द्वारा रिवर्सिंग कभी-कभी स्वीकार्य हो सकता है ... लेकिन यूक्रेन ऑस्ट्रेलिया क्यों बन गया?

println!("{}", reverse_string("abc/df/ghi")); // prints cba/fd/ihg 

(प्रत्येक झंडा इमोजी दो कोड अंक है कि एक देश कोड वर्तनी से बना है, और ऑस्ट्रेलिया के (एयू) यूक्रेन के (UA) के विपरीत है। अजीब बातें भी, गैर इमोजी के साथ हो सकता ñ की तरह ।)

सौभाग्य से, unicode-segmentation क्रेट के साथ ठीक करना आसान है; चलो बस Matthieu's solution ले, push_str साथ graphemes(true) और push साथ chars() की जगह:

extern crate unicode_segmentation; 
use unicode_segmentation::UnicodeSegmentation; 

fn reverse_string(input: &str) -> String { 
    let mut result = String::with_capacity(input.len()); 

    for portion in input.split('/') { 
     if !result.is_empty() { 
      result.push('/'); 
     } 
     for g in portion.graphemes(true).rev() { 
      result.push_str(g); 
     } 
    } 

    result 
} 

अब हमारे सभी झंडे सही फिर से (playground) देखो।

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