2017-02-01 36 views
0

私のユースケースは、より複雑ですが、基本的に以下の私が達成しようとしているかの簡単な例である(私の元のコードは、アッカ・ストリームのためです):テール再帰(@tailrec)再帰関数対非再帰関数スカラースタックオーバーフローエラー?

offset := 0 

//pump data 
def pump(): Unit = { 
    elem := poller.getNumberFromOffset(offset) 

    elem match { 
     case null => doSomething() 
     case Completed => doSomethingElse() 
     case _ => 
      offset += 1 
      //check if the element is matched with a pre-supplied selector/filter function 
      if(filterFunc(elem)) { 
       doSomething2() 
      } else { 
       //if the element doesn't match; increase offset and try again; can sleep for a while here    
       pump() 
      } 
    } 
} 

問題は、ポンプ()関数がかもしれないですスタックオーバーフローが発生します(特定の条件でポンプ機能が再度オーバーラップするため)。

私は次のような非再帰バージョンに関数を記述することができます。私のユースケースは、はるかに複雑であるしかし

offset := 0 

//pump data 
def pump(): Unit = { 
    elem := poller.getNumberFromOffset(offset) 
    while(elem != null && elem != Completed && !filterFunc(elem)) { 
     offset += 1 
     elem = poller.getNumberFromOffset(offset) 
    }  

    elem match { 
     case null => doSomething() 
     case Completed => doSomethingElse() 
     case _ =>   
      offset += 1 
      doSomething2() 
    } 
} 

。既存のコードをwhile/forループに変換するのではなく、可能であれば再帰関数を使用したいと思っています。

@tailrecアノテーションを最初の例に置くだけで、scalaコンパイラがtail-recursion関数(@tailrec def pump())として扱うようにすれば、私の質問は「そうするべきですか?単位= {})。私の場合、pump()関数は固定間隔の後に分離して呼び出す必要があります。スタックフレームは実際には必要ありません。

ありがとうございました。

+4

"最初の例に' @ tailrec'アノテーションを置くだけで何か違いはありますか? - いいえ、 '@ tailrec'アノテーションは違いはありません。テール再帰的方法は常に最適化されています。 (もっと正確には:[仕様書に記載された条件を満たす]メソッド(http://scala-lang.org/files/archive/spec/2.13/06-expressions.html#function-applications)。)唯一のこと'@ tailrec'アノテーションは、メソッドがtail-recursiveでない場合、コンパイラエラーを生成します。 [メソッドが最適化されるかどうかを変更しない*](http://scala-lang.org/api/current/scala/annotation/tailrec.html) –

+0

私はあなたのパターンマッチングに挑戦します。代わりに、私はあなたの可能な 'null'値を[Option#apply](http://www.scala-lang.org/api/2.11.8/index.html#[email protected] [A] x:A):オプション[A])。例: 'Option [String] {null}' === 'None' –

答えて

1

@tailrecを入力すると、コンパイラで実行できるようになります。これは、コードがテール再帰最適化に適格であることを意味します。内部スカラコンパイラは、テール再帰コードをループに変換します。私は尾の再帰関数は、@tailrecを満たしていれば、stackoverflow error.Soあなたのポンプ()関数の原因になることはありません考えていない。