2017-03-02 3 views
0

startend 사이의 각 숫자에 반복적으로 pub fn verse(num: i32) -> String을 호출 한 결과 문자열을 반환하는 pub fn sing(start: i32, end: i32) -> String을 만들려고합니다.어떻게 역방향 범위를 반복 할 수 있습니까?

나는 대답을 검색 좀했는데 Rust String concatenation 내 질문에 대답한다는 것, 그리고 심지어 playground에 내 코드를 작성하는 경우가 작동하지만

:

내 코드 :

pub fn verse(num: i32) -> String { 
    match num { 
     0 => "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n".to_string(), 
     1 => "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n".to_string(), 
     2 => "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n".to_string(), 
     num => format!("{0} bottles of beer on the wall, {0} bottles of beer.\nTake one down and pass it around, {1} bottles of beer on the wall.\n",num,(num-1)), 
    } 
} 

pub fn sing(start: i32, end: i32) -> String { 
    (start..end).fold(String::new(), |ans, x| ans+&verse(x)) 
} 

문제를

#[test] 
fn test_song_8_6() { 
    assert_eq!(beer::sing(8, 6), "8 bottles of beer on the wall, 8 bottles of beer.\nTake one down and pass it around, 7 bottles of beer on the wall.\n\n7 bottles of beer on the wall, 7 bottles of beer.\nTake one down and pass it around, 6 bottles of beer on the wall.\n\n6 bottles of beer on the wall, 6 bottles of beer.\nTake one down and pass it around, 5 bottles of beer on the wall.\n"); 
} 

beer::sing(8,6)""를 반환 실패한다는 것입니다.

답변

4

문제는 문자열 연결과 관련이 없습니다. 범위가 앞으로 만 반복하기 때문에 8..6이 빈 반복자라는 사실과 관련이 있습니다. 8 >= 6이므로 이터레이터는 을 첫 번째 호출에서 next으로 반환합니다.

fn main() { 
    for i in 8..6 { 
     println!("{}", i); // never reached 
    } 
} 

startend을 교환하고 뒤로 반복 rev()를 호출하여 해결할 수 있습니다.

fn main() { 
    for i in (6..8).rev() { 
     println!("{}", i); 
    } 
} 

그러나 또 다른 문제가 있습니다. start..end 범위에서 start은 포함되지만 end은 배타적입니다. 예를 들어, 위의 코드는 76을 인쇄합니다. 8이 인쇄되지 않습니다. 범위 반복자가 끝에 추가 값을 방출하도록 끝점에 하나를 추가해야합니다. (야간 컴파일러와 함께) 포괄적 인 범위를 사용하여

pub fn sing(start: i32, end: i32) -> String { 
    (end..start + 1).rev().fold(String::new(), |ans, x| ans+&verse(x)) 
} 

또는 : (.이 또한 RangeInclusive하지만이 녹 1.15.1의 같은 불안정)

이 모두 함께 퍼팅, sing는 같아야합니다

#![feature(inclusive_range_syntax)] 

pub fn sing(start: i32, end: i32) -> String { 
    (end...start).rev().fold(String::new(), |ans, x| ans+&verse(x)) 
} 

참고 : 각 절 사이에 두 개의 개행이 있어야하기 때문에 테스트가 계속 실패하지만 코드에서 생성합니다. 나는이 문제를 고쳐 줄 것이다.

+0

고마워요. 범위가 앞으로 만 반복되는 이유는 무엇입니까? –

+1

@CalebJasik : 실제로는 앞으로 만 반복되는 것이 아니라 일반적인 half-open 범위를 모델링하는 것 이상입니다. 이런 의미에서'start == end'는 빈 범위를 나타내며'start> = end' 버그를 나타냅니다. 또한 Range 코드를 더 간단하게 만듭니다. 역방향 반복의 경우,'rev'를 명시 적으로 호출하면 완료됩니다. –