如何迭代向后范围?

0 iterator match rust

我正在尝试创建pub fn sing(start: i32, end: i32) -> String它返回一个串联的字符串,pub fn verse(num: i32) -> String重复调用每个数字之间startend.

我用google搜索答案,看起来Rust String连接回答了我的问题,如果我甚至在操场上编写我的代码就行了,但是:

我的代码:

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))
}
Run Code Online (Sandbox Code Playgroud)

问题是

#[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");
}
Run Code Online (Sandbox Code Playgroud)

失败了beer::sing(8,6)回来"".

Fra*_*gné 7

您的问题与字符串连接无关.它与8..6空迭代器的事实有关,因为范围只向前迭代.因为8 >= 6,迭代器None在第一次调用时产生next.

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

这可以通过交换固定startend并呼吁rev()向后遍历.

fn main() {
    for i in (6..8).rev() {
        println!("{}", i);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,还有另一个问题.在一个范围内start..end,start是包容性的但是end是排他性的.例如,上面的代码打印76; 8没有打印.请参阅如何在范围中包含最终值?

把它们放在一起,sing应该看起来像:

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

注意:您的测试仍然失败,因为它预计每个节目之间有两个换行符,但您的代码只生成一个.我会把这个留给你解决.

  • @CalebJasik:它并不是真正只是向前迭代,而不仅仅是模拟一个典型的半开放范围:`[start end)`.从这个意义上讲,`start == end`代表一个空范围,`start> = end`代表一个bug.它还使Range代码更简单(因此更快).对于反向迭代,你明确地调用`rev`,你就完成了. (2认同)