사용자 지정 단계로 범위를 반복하려면 어떻게합니까?


106

1이 아닌 단계로 Rust에서 범위를 어떻게 반복 할 수 있습니까? 나는 C ++ 배경에서 왔기 때문에 다음과 같은 것을하고 싶습니다.

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

Rust에서는 range함수 를 사용해야 하는데 사용자 지정 단계를 갖는 데 사용할 수있는 세 번째 인수가없는 것 같습니다. 어떻게 할 수 있습니까?

답변:



13

.step_by방법이 안정 될 때까지 원하는 것을 쉽게 수행 할 수 있습니다 Iterator( Range어쨌든 실제로 는 무엇입니까 ).

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);
    }
}

다른 유형의 여러 범위를 반복해야하는 경우 다음과 같이 코드를 일반화 할 수 있습니다.

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);
    }
}

무한 루프가 필요한 경우 개방형 구조를 생성하기 위해 상한 검사를 제거하도록 맡기겠습니다.

이 접근 방식의 장점은 for설탕 처리와 함께 작동하며 불안정한 기능을 사용할 수있게 되더라도 계속 작동한다는 것입니다. 또한 표준을 사용하는 de-sugared 접근 방식과 달리 Range여러 .next()호출로 인해 효율성을 잃지 않습니다 . 단점은 반복자를 설정하는 데 몇 줄의 코드가 필요하므로 루프가 많은 코드에만 가치가있을 수 있다는 것입니다.


다른 유형을 추가하면 U두 번째 옵션에 다른 유형의 추가를 지원하는 유형을 사용할 수 있으며 여전히 T. 예를 들어 시간과 기간이 떠 오릅니다.
라이언

@Ryan, 좋은 생각처럼 보이며 다음과 같이 정의 된 구조체와 함께 작동해야합니다. struct StepRange <T> (T, T, U) where for < 'a,'b> & 'a T : Add <&' b U, 출력 = T>, T : PartialOrd, T : 복제; 입력 T 및 U 유형에 대해 서로 다른 수명을 허용해야합니다.
GordonBGood

4

C ++ 코드를 작성합니다.

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

... 러스트에서 다음과 같이 :

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

Rust 버전도 더 읽기 쉽다고 생각합니다.


Re : 루프에 "continue"를 삽입하면 for 구조에서도 조건부 분기 내에서만이 작업을 수행 할 수 있습니다. 그렇다면 "continue"-ing 전에 while 구조의 조건부 분기 내에서 증가해도 괜찮을 것이라고 생각합니다. 그러면 의도 한대로 작동 할 것입니다. 아니면 내가 뭔가를 간과하고 있습니까?
WDS

1
@WDS는 언어의 기본 기능을 continue제대로 사용 하기위한 반 직관적 인 바쁜 작업입니다. 할 수 있지만이 디자인은 버그를 유발합니다.
Chai T. Rex


2

미리 정의 된 2와 같이 작은 단계로 이동하는 경우 반복기를 사용하여 수동으로 단계를 수행 할 수 있습니다. 예 :

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

이것을 사용하여 임의의 양만큼 단계적으로 이동할 수도 있습니다 (확실히 길어지고 소화하기 어려워 짐).

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();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.