2017-03-02 73 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',你就完成了。 –