কোনও আইট্রেটার (বা অন্য কোনও বৈশিষ্ট্য) ফেরত দেওয়ার সঠিক উপায় কী?


114

নিম্নলিখিত মরিচা কোড কম্পাইল করে এবং কোনও সমস্যা ছাড়াই চলে।

fn main() {
    let text = "abc";
    println!("{}", text.split(' ').take(2).count());
}

এর পরে, আমি এই জাতীয় কিছু চেষ্টা করেছি .... তবে এটি সংকলন হয়নি

fn main() {
    let text = "word1 word2 word3";
    println!("{}", to_words(text).take(2).count());
}

fn to_words(text: &str) -> &Iterator<Item = &str> {
    &(text.split(' '))
}

মূল সমস্যাটি হ'ল আমি নিশ্চিত নই যে ফাংশনটি কী ধরনের হওয়া to_words()উচিত type সংকলক বলেছেন:

error[E0599]: no method named `count` found for type `std::iter::Take<std::iter::Iterator<Item=&str>>` in the current scope
 --> src/main.rs:3:43
  |
3 |     println!("{}", to_words(text).take(2).count());
  |                                           ^^^^^
  |
  = note: the method `count` exists but the following trait bounds were not satisfied:
          `std::iter::Iterator<Item=&str> : std::marker::Sized`
          `std::iter::Take<std::iter::Iterator<Item=&str>> : std::iter::Iterator`

এই রান করার সঠিক কোডটি কী হবে? .... আর আমার জ্ঞানের ফাঁক কোথায়?

উত্তর:


143

সংকলকটি আমাকে গাইড করতে কার্যকরভাবে খুঁজে পেয়েছি:

fn to_words(text: &str) { // Note no return type
    text.split(' ')
}

সংকলন দেয়:

error[E0308]: mismatched types
 --> src/lib.rs:5:5
  |
5 |     text.split(' ')
  |     ^^^^^^^^^^^^^^^ expected (), found struct `std::str::Split`
  |
  = note: expected type `()`
             found type `std::str::Split<'_, char>`
help: try adding a semicolon
  |
5 |     text.split(' ');
  |                    ^
help: try adding a return type
  |
3 | fn to_words(text: &str) -> std::str::Split<'_, char> {
  |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

সংকলকের পরামর্শ এবং অনুলিপি অনুসরণ করে যে আমার রিটার্ন টাইপ হিসাবে (একটু পরিষ্কারের সাথে):

use std::str;

fn to_words(text: &str) -> str::Split<'_, char> {
    text.split(' ')
}

সমস্যাটি হ'ল আপনি এমন বৈশিষ্ট্যটি ফিরিয়ে দিতে পারবেন না Iteratorকারণ একটি বৈশিষ্ট্যের আকার থাকে না। এর অর্থ রাস্টটি জানেন না যে প্রকারের জন্য কত স্থান বরাদ্দ করতে হবে। আপনি স্থানীয় ভেরিয়েবলের কোনও রেফারেন্স ফিরিয়ে দিতে পারবেন না , সুতরাং প্রত্যাবর্তন &dyn Iteratorহ'ল স্টার্টার।

ইমপ্লিট বৈশিষ্ট্য

মরিচা 1.26 হিসাবে, আপনি ব্যবহার করতে পারেন impl trait:

fn to_words<'a>(text: &'a str) -> impl Iterator<Item = &'a str> {
    text.split(' ')
}

fn main() {
    let text = "word1 word2 word3";
    println!("{}", to_words(text).take(2).count());
}

এটি কীভাবে ব্যবহার করা যায় তার উপর বিধিনিষেধ রয়েছে। আপনি কেবল একটি একক প্রকার (কোনও শর্তসাপেক্ষ!) ফেরত দিতে পারেন এবং এটি অবশ্যই একটি ফাংশন বা সহজাত প্রয়োগের জন্য ব্যবহার করা উচিত।

boxed

আপনি যদি কিছুটা দক্ষতা হারাতে আপত্তি না করেন তবে আপনি ফিরে আসতে পারেন Box<dyn Iterator>:

fn to_words<'a>(text: &'a str) -> Box<dyn Iterator<Item = &'a str> + 'a> {
    Box::new(text.split(' '))
}

fn main() {
    let text = "word1 word2 word3";
    println!("{}", to_words(text).take(2).count());
}

এটি প্রাথমিক বিকল্প যা গতিশীল প্রেরণের অনুমতি দেয় । অর্থাৎ কোডটির সঠিক প্রয়োগটি সংকলন-সময়ের পরিবর্তে রান-টাইমে সিদ্ধান্ত নেওয়া হয়। এর অর্থ এটি এমন ক্ষেত্রে উপযুক্ত যেখানে আপনার শর্তের ভিত্তিতে একাধিক কংক্রিট ধরণের পুনরাবৃত্তি করতে হবে।

নতুন ধরনের

use std::str;

struct Wrapper<'a>(str::Split<'a, char>);

impl<'a> Iterator for Wrapper<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

fn to_words(text: &str) -> Wrapper<'_> {
    Wrapper(text.split(' '))
}

fn main() {
    let text = "word1 word2 word3";
    println!("{}", to_words(text).take(2).count());
}

উপনাম টাইপ করুন

রিম দ্বারা নির্দেশিত হিসাবে

use std::str;

type MyIter<'a> = str::Split<'a, char>;

fn to_words(text: &str) -> MyIter<'_> {
    text.split(' ')
}

fn main() {
    let text = "word1 word2 word3";
    println!("{}", to_words(text).take(2).count());
}

ক্লোজারগুলির সাথে ডিল করছে

যখন impl Traitব্যবহারের জন্য উপলব্ধ না হয়, বন্ধগুলি জিনিসগুলিকে আরও জটিল করে তোলে। বন্ধগুলি বেনামে প্রকার তৈরি করে এবং এগুলি ফেরতের প্রকারে নাম দেওয়া যায় না:

fn odd_numbers() -> () {
    (0..100).filter(|&v| v % 2 != 0)
}
found type `std::iter::Filter<std::ops::Range<{integer}>, [closure@src/lib.rs:4:21: 4:36]>`

কিছু ক্ষেত্রে, এই ক্লোজারগুলি ফাংশনগুলির সাথে প্রতিস্থাপন করা যেতে পারে, যার নাম দেওয়া যেতে পারে:

fn odd_numbers() -> () {
    fn f(&v: &i32) -> bool {
        v % 2 != 0
    }
    (0..100).filter(f as fn(v: &i32) -> bool)
}
found type `std::iter::Filter<std::ops::Range<i32>, for<'r> fn(&'r i32) -> bool>`

এবং উপরোক্ত পরামর্শ অনুসরণ:

use std::{iter::Filter, ops::Range};

type Odds = Filter<Range<i32>, fn(&i32) -> bool>;

fn odd_numbers() -> Odds {
    fn f(&v: &i32) -> bool {
        v % 2 != 0
    }
    (0..100).filter(f as fn(v: &i32) -> bool)
}

শর্তসাপেক্ষে কাজ করা

যদি আপনাকে শর্তসাপেক্ষে একটি পুনরুক্তি প্রদানকারী চয়ন করতে হয় তবে শর্তাধীন বেশ কয়েকটি সম্ভাব্য পুনরুক্তির মধ্যে একটির উপর শর্তসাপেক্ষে পুনরাবৃত্তি পড়ুন ।


আপনাকে ধন্যবাদ, এটি আমাকে অনেক সাহায্য করেছে। সংকলক আপনাকে গাইড করতে "কৌশল "টি বেশ কার্যকর, আমি অবশ্যই ভবিষ্যতে এটি ব্যবহার করব। ... এবং হ্যাঁ, এটি মারাত্মকভাবে কুৎসিত! আমি আশা করি আরএফসি এটি মুক্তির প্রার্থীর হয়ে উঠেছে।
ফোরজেমো

8
যদিও মোড়কের প্রকারের জটিলতাগুলি আড়াল করার পক্ষে দুর্দান্ত হতে পারে তবে আমি typeতার পরিবর্তে কেবলমাত্র এলিয়াস ব্যবহার করা ভাল বলে মনে করি , কারণ একটি নতুন প্রকারের অর্থ আপনার আইট্রেটরের RandomAccessIteratorঅন্তর্নিহিত Iterator না করে এমনকি বৈশিষ্ট্যগুলি প্রয়োগ করে না।
রিম

4
হা! প্রকারের এলিয়াসগুলি জেনেরিক পরামিতিগুলিকে সমর্থন করে। উদাহরণস্বরূপ, অনেক লাইব্রেরি type LibraryResult<T> = Result<T, LibraryError>সুবিধামত হিসাবে অনুরূপ হিসাবে কাজ করে IoResult<T>, এটি কেবল একটি প্রকারের উপনাম।
রিম

1
আপনি দয়া করে ব্যাখ্যা করতে পারেন কেন একজনকে 'aআজীবন যুক্ত করতে হবে Box? ওটার মানে কি? আমি সবসময় চিন্তা এই বলে "টি শুধুমাত্র দীর্ঘ হিসাবে হিসাবে অন্তত কিছু জীবন্ত উপর নির্ভর করতে পারে শুধুমাত্র সীমা ছিল, 'a"।
টর্কলি

1
@torkleyy সম্ভবত stackoverflow.com/q/27790168/155423 বা stackoverflow.com/q/27675554/155423 আপনার প্রশ্নের উত্তর দিতে হবে? যদি তা না হয় তবে আমি আপনাকে আপনার প্রশ্ন অনুসন্ধান করতে উত্সাহিত করব এবং যদি এটি খুঁজে না পান তবে একটি নতুন প্রশ্ন করুন।
শেপমাস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.