私のユースケースは、より複雑ですが、基本的に以下の私が達成しようとしているかの簡単な例である(私の元のコードは、アッカ・ストリームのためです):テール再帰(@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()関数は固定間隔の後に分離して呼び出す必要があります。スタックフレームは実際には必要ありません。
ありがとうございました。
"最初の例に' @ 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) –
私はあなたのパターンマッチングに挑戦します。代わりに、私はあなたの可能な 'null'値を[Option#apply](http://www.scala-lang.org/api/2.11.8/index.html#[email protected] [A] x:A):オプション[A])。例: 'Option [String] {null}' === 'None' –