Özel bir adımla bir aralıkta nasıl yineleme yaparım?


100

1 dışında bir adımla Rust'ta bir aralıkta nasıl yineleme yapabilirim? C ++ arka planından geliyorum, bu yüzden şöyle bir şey yapmak istiyorum

for(auto i = 0; i <= n; i+=2) {
    //...
}

Rust'ta rangeişlevi kullanmam gerekiyor ve özel bir adıma sahip olmak için üçüncü bir argüman yok gibi görünüyor. Bunu nasıl başarabilirim?

Yanıtlar:



12

Bana öyle geliyor ki, .step_byyöntem kararlı hale gelene kadar , bir kişi istediğiniz şeyi kolayca başarabilir Iterator( Rangezaten gerçekte olan budur ):

struct SimpleStepRange(isize, isize, isize);  // start, end, and step

impl Iterator for SimpleStepRange {
    type Item = isize;

    #[inline]
    fn next(&mut self) -> Option<isize> {
        if self.0 < self.1 {
            let v = self.0;
            self.0 = v + self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in SimpleStepRange(0, 10, 2) {
        println!("{}", i);
    }
}

Birinin farklı türde birden çok aralığı yinelemesi gerekiyorsa, kod aşağıdaki gibi genel yapılabilir:

use std::ops::Add;

struct StepRange<T>(T, T, T)
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone;

impl<T> Iterator for StepRange<T>
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.0 < self.1 {
            let v = self.0.clone();
            self.0 = &v + &self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in StepRange(0u64, 10u64, 2u64) {
        println!("{}", i);
    }
}

Sonsuz bir döngü gerekliyse, açık uçlu bir yapı oluşturmak için üst sınır kontrolünü ortadan kaldırmayı size bırakacağım ...

Bu yaklaşımın avantajları, forşekerleme ile çalışan ve dengesiz özellikler kullanılabilir hale geldiğinde bile çalışmaya devam edecek olmasıdır; ayrıca, standart ' Rangeleri kullanan şekersiz yaklaşımın aksine, birden fazla .next()çağrı ile verimliliği kaybetmez . Dezavantajları, yineleyiciyi kurmak için birkaç satır kod gerektirmesidir, bu nedenle yalnızca çok sayıda döngüye sahip kod için buna değebilir.


Başka bir tür ekleyerek U, ikinci seçeneğinize, farklı bir türle toplamayı destekleyen ve yine de bir T. Mesela zaman ve süre akla geliyor.
Ryan

@Ryan, bu iyi bir fikir gibi görünüyor ve aşağıdaki gibi tanımlanan yapı ile çalışmalıdır: struct StepRange <T> (T, T, U) burada <'a,' b> & 'a T: Add <&' b U, Çıktı = T>, T: KısmiOrd, T: Klon; Bu, giriş T ve U tipleri için farklı ömürlere izin vermelidir.
GordonBGood


3

C ++ kodunuzu yazarsınız:

for (auto i = 0; i <= n; i += 2) {
    //...
}

... Rust'ta şöyle:

let mut i = 0;
while i <= n {
    // ...
    i += 2;
}

Rust versiyonunun da daha okunaklı olduğunu düşünüyorum.


Re: Döngüye "devam et" eklemek, bunu sadece bir koşullu dalda yapacağını düşünüyorum for yapısında bile. Eğer öyleyse, o zaman "devam" yapmadan önce while yapısındaki koşullu dal içinde artmanın uygun olacağını ve daha sonra amaçlandığı gibi çalışacağını düşünüyorum. Yoksa bir şeyi gözden mi kaçırıyorum?
WDS

1
@WDS, dilin temel bir özelliğini elde etmek, continuedüzgün çalışmak için mantıksız bir iştir. Yapılabilse de, bu tasarım böcekleri teşvik eder.
Chai T. Rex

2

Önceden tanımlanmış ve 2 gibi küçük bir şeyle adım atıyorsanız, manuel olarak adım atmak için yineleyiciyi kullanmak isteyebilirsiniz. Örneğin:

let mut iter = 1..10;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    iter.next();
}

Bunu rastgele bir miktar adım atmak için bile kullanabilirsiniz (bunun kesinlikle uzaması ve sindirilmesi zorlaşmasına rağmen):

let mut iter = 1..10;
let step = 4;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    for _ in 0..step-1 {
        iter.next();
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.