2017-03-02 1 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()を呼び出すことによって固定することができます。

​​

しかし、まだ別の問題があります。 start..endの範囲では、startが含まれますが、endは排他的です。たとえば、上のコードは76を出力します。 8は印刷されません。範囲イテレータが最後に追加の値を出力するように、エンドポイントに1つを追加する必要があります。

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

注:各節の間に2つの改行が必要ですが、あなたのコードでは1つしか生成されないため、テストは失敗します。私はあなたにこれを修正してもらいます。

+0

ありがとうございます。レンジは前方のみを反復するのはなぜですか? –

+1

@CalebJasik:それは実際にはそれが前進を繰り返すだけではなく、典型的な半開きの範囲をモデル化する以上のものです。この意味で、 'start == end'は空の範囲を表し、' start> = end'はバグです。また、Rangeコードをよりシンプルに(したがって高速に)作成します。逆の反復では、 'rev'を明示的に呼び出すと、完了です。 –

関連する問題