2017-03-02 142 views
0

我正在尝试创建pub fn sing(start: i32, end: i32) -> String,它会在startend之间的每个数字上重复调用pub fn verse(num: i32) -> String的结果的连接字符串。如何迭代向后范围?

我GOOGLE的答案,似乎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产生None

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

这可以通过交换startend并调用rev()向后迭代被固定。

​​

但是,还有另一个问题。在一系列start..endstart是包容性的,但end是排斥的。例如,上面的代码打印76;不打印8。您需要将一个添加到端点,以便范围迭代器在最后发出一个附加值。 (还有RangeInclusive,但它是不稳定的防锈1.15.1)的

全部放在一起,sing应该是这样的:

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

,或者使用包括的范围(含夜间编译):

#![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:它不是真的只是向前迭代,而是比典型的半开放范围模型:'[开始结束]'。在这个意义上,'start == end'表示一个空的范围,'start> = end'表示一个错误。它也使得范围代码更简单(从而更快)。对于反向迭代,你明确地调用'rev',你就完成了。 –