私はScalaを学習し始めたばかりであり、私が従う多くのチュートリアルはmain
メソッドに異なる表現の組み合わせを使用しています。おなじみのメインメソッドは別として。トレイトApp
またはApplication
の使用もあります。Application
は非推奨であり、推奨されていないようですが、これ以上の説明となる情報は見つかりませんエントリポイントを定義するこれらの方法のそれぞれについて。
だから、誰かが私に説明できるかどうか疑問に思っています:
App
とApplication
はどのように機能しますか?Application
が推奨されなくなったのはなぜですか、またApp
トレイトは何が違うのですか?App
を使用してプログラムを開始する必要がありますか? 2つのアプローチの違いは何ですか?Application
トレイトの問題は、実際にはそのドキュメントに記載されています:
(1)オブジェクトを参照するスレッドコードは、静的な初期化が完了するまでブロックされます。ただし、アプリケーションを拡張するオブジェクトの実行全体は静的初期化中に行われるため、並行コードは、それを囲むオブジェクトと同期する必要がある場合、常にデッドロックになります。
これはトリッキーです。 Application
トレイトを拡張すると、基本的にJavaクラスを作成します:
class MyApplication implements Application {
static {
// All code goes in here
}
}
JVMは、上記のクラス初期化子をMyApplication
クラスで暗黙的に同期して実行します。これにより、クラスが初期化される前にMyApplication
のインスタンスが作成されないことが保証されます。 MyApplication
のインスタンスに再びアクセスする必要があるアプリケーションからスレッドを生成した場合、プログラム全体が実行された後にのみクラスの初期化が完了するため、アプリケーションはデッドロックになります。これは、プログラムが実行されている限りインスタンスを作成できないため、パラドックスを意味します。
(2)上記のように、Applicationを拡張するオブジェクトの本体のすべてのコードは、Applicationのメインメソッドが実行を開始する前に発生する静的初期化の一部として実行されるため、コマンドライン引数を取得する方法はありません。
クラス初期化子は引数を取りません。また、静的フィールド値を割り当てる前にクラス初期化子を実行する必要があるため、値がクラスに渡される前に最初に実行されます。したがって、args
メソッドで通常受け取るmain
は失われます。
(3)静的初期化子はプログラムの実行中に1回だけ実行され、JVMの作成者は通常、実行時間が比較的短いと想定しています。したがって、特定のJVM構成が混乱するか、アプリケーションを拡張するオブジェクトの本体のコードを最適化またはJITできないだけです。これにより、パフォーマンスが大幅に低下する可能性があります。
JVMは、頻繁に実行されるコードを最適化します。これにより、実際にはパフォーマンスのボトルネックではないメソッドの実行時間が無駄にならないことが保証されます。ただし、static
メソッドは手動で呼び出すことができないため、一度だけ実行されると想定しています。したがって、クラス初期化子から実行されるコードは最適化されませんが、main
トレイトを使用している場合は、アプリケーションのApplication
メソッドコードになります。
App
トレイトは DelayedInit
を拡張することでこれをすべて修正します。この特性は、Scalaコンパイラーに明示的に認識されているため、初期化コードはクラス初期化子からではなく別のメソッドから実行されます。名前のに注意してくださいトレイトの唯一のメソッドへの参照:
trait Helper extends DelayedInit {
def delayedInit(body: => Unit) = {
println("dummy text, printed before initialization of C")
body
}
}
DelayedInit
を実装する場合、Scalaコンパイラは、その実装クラスまたはオブジェクトの初期化コードをfor name関数がdelayedInit
メソッドに渡されます。初期化コードは直接実行されません。このように、イニシャライザが実行される前にコードを実行して、Scalaたとえば、アプリケーションのランタイムメトリックをコンソールに出力して、プログラムのエントリポイントと終了をラップします。ただし、 このアプローチのいくつかの警告 があるため、DelayedInit
の使用は非推奨です。実際には、App
トレイトによって課される問題を解決するApplication
トレイトのみに依存する必要があります。DelayedInit
を直接実装しないでください。
main
で定義する限り、必要に応じてobject
メソッドを定義できます。これは主にスタイルの問題です:
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}