PHPer の中には Go または Java への切り替えを検討する人もいるでしょう。これら 2 つの言語を簡単に比較してみましょう。この記事はあくまで参考です!
Go 言語
Java と比較すると、Go 言語はマシンコードにコンパイルされ、直接実行されます。 C言語とよく似ています。仮想マシンがないため、これは Java とは大きく異なります。これはオブジェクト指向であり、ある意味、自動ガベージ コレクションを備えた単なる新しい C 言語ではありません。 Java プログラマーの観点から見ると、Go 言語の学習は非常に困難になるほど異なる点があり、オブジェクト、クラス、その他すべてのプログラミング言語の構成要素をより深く理解するのに役立ちます。 Java であっても、言語コンポーネントで何が起こっているのか。
私が言いたいのは、Go 言語でのオブジェクト指向の実装を理解すれば、Java 言語でのこれらのさまざまな実装も理解できるということです。
#ガベージ コレクションを使用するかどうか
メモリ管理の部分はプログラミング言語において非常に重要です。アセンブリ言語を使用すると、すべてを行うことができます。むしろ、アセンブリ言語ではすべてを行う必要があります。 C 標準ライブラリには、メモリ管理のためのいくつかの基本関数が用意されていますが、それでも、malloc を呼び出してメモリを割り当てた後、それらの関数を手動で解放する必要があります。自動メモリ管理手法は、C、Python、Swift、Java で登場しました。 Go 言語もその 1 つです。 Java およびその他の JVM 言語 (Python の JVM 実装を含む) の場合、メモリは JVM によって管理されます。 JVM は非常に成熟したガベージ コレクションを備えています。ガベージ コレクションは常に 1 つ以上のスレッドで実行されます。ワーカー スレッドと並行して、または場合によってはこれらのワーカー スレッドを一時停止して、到達不能なオブジェクトにマークを付け、クリアして、検出されたオブジェクトを分散させます。メモリは一緒に圧縮しました。心配する必要があるのはパフォーマンスだけです。 Go 言語でもこの方法が使用されていますが、微妙な違いがいくつかあります。 Go 言語には参照はありませんが、ポインタはあります。この違いは非常に重要です。 Go 言語は追加の C コードと統合できますが、パフォーマンス上の理由から、実行時に参照などは何も登録されません。実際のポインタは、実行中のシステムに対して透過的です。割り当てられたメモリは引き続き分析して到達可能性情報を収集でき、不要なオブジェクトをマークしてクリアすることはできますが、圧縮のためにメモリを他の場所に移動することはできません。 Go 言語にはガベージ コレクションがありますが、メモリを圧縮しないため、Java のような完全な GC ではありません。これは必ずしも悪いことではありません。これは、メモリの断片化を引き起こすことなくサーバーを長時間実行するのに合理的だからです。一部の JVM ガベージ コレクターは、古い世代をクリアする際の GC の一時停止を減らすために圧縮ステップをスキップし、最後の手段としてのみ圧縮を使用します。 Go にはこの最後の手段のステップが実装されていないため、まれなシナリオで問題が発生する可能性があります。この言語を学習すると、この問題に遭遇する可能性は低くなります。ローカル変数
Java 言語では、ローカル変数 (新しいバージョンでは場合によってはオブジェクト) はスタックに格納されます。これは、C、C++、およびコール スタック自体を実装するその他の言語にも当てはまります。 Go も例外ではありません。関数からローカル変数へのポインタを単に返す場合を除きます。これはC言語では致命的なエラーです。 Go の場合、Go コンパイラーは、割り当てられた「オブジェクト」 (ここで引用符が使用される理由については後で説明します) がメソッドからエスケープされ、それに応じてそれ (メモリ) を割り当てることを検出します。そのため、この「オブジェクト」は関数内にあり、その後もまだ生きています。戻り、それへのポインタが信頼性の低いデータを含む古いメモリを指していません。クロージャ
関数型言語と同じように (Go 言語は関数型言語です)、関数内に関数を記述してこの関数を返すことができ、その後ローカルvariable は、この関数のクロージャ変数です。関数の戻り値
関数は、単一の値を返すだけでなく、複数の値を返すこともできます。これは、適切に使用しないと悪い習慣になるようです。これは Python と Perl の両方に当てはまります。複数の値を返すと、状況によっては便利です。主に戻り値と「nil」またはエラーコードに使用されます。このようにして、エラーを戻り値の型にエンコードするという過去の習慣 (通常、C 標準ライブラリ呼び出しのようにエラー コードとして -1 を返し、他の意味を表すその他の非負の値を返す) は、このより読みやすいメソッドに置き換えられます。 。オブジェクト指向
クラス定義にメソッドを詰め込むのではなく、メソッド自体を定義するときに構造を指定できます。構造体には他の構造体を含めることもできます。参照したいフィールドに名前がない場合は、その型で参照することができ、それが暗黙的にフィールドの名前になります。または、このフィールドまたはメソッドが最上位の構造体に属している限り、それを参照できます。
メソッドを呼び出すことができる構造体を指定する場合は、構造体を通じて自分で指定するか、または構造体へのポインタ。メソッドが構造体に適用される場合、メソッドは呼び出し元の構造体のコピー (値によって渡されます) を取得します。メソッドが構造体へのポインターに適用される場合、ポインターは渡されます (参照渡しと同様)。後者の場合、メソッドは構造体を変更することもできます (値の型は不変であるため、この意味では、構造体は値の型ではありません)。どちらもインターフェイスのニーズを満たすために使用できます。
Go の構文は、構造体とポインターに対してもより寛容です。 C では、b.a を使用して、所有する構造体の a フィールドにアクセスできます。 C の構造体へのポインターの場合、同じフィールドにアクセスするには b->a を使用する必要があります。 b.a はポインタを使用するとエラーを報告します。 Go は、b->a と書くのは無意味だと考えています (はい、それが意味します)。 . 演算子がオーバーロードされる可能性があるのに、-> 演算子によってコードが乱雑に見えるのはなぜですか?構造体がこの方法でフィールドにアクセスできる場合は、ポインターを介してこの方法でアクセスする必要があります。これは非常に論理的です。
型はオブジェクトではなく変数にあります
そのため、「オブジェクト」を引用符で囲んでいます。 Go が構造体を保存するとき、それはメモリの一部であり、オブジェクト ヘッダーはなく、実際には、変数には値の型が含まれます。変数が構造体型である場合、それはコンパイル時にすでにわかっています。変数がインターフェイス型の場合、変数はその値を指し、値の実際の型を参照します。
インターフェースの実装
Go におけるインターフェースは非常にシンプルですが、非常に複雑です。インターフェイスは、インターフェイスと互換性を持たせるために構造体が実装する必要がある一連のメソッドを宣言します。インターフェイスの継承は、構造体の継承と同じです。奇妙なのは、構造体がインターフェイスを実装するときに、それを明示的に指定する必要がないことです。実際、インターフェイスを実装するのはインターフェイスではなく、構造体または構造体へのポインターをレシーバーとして使用するこの一連の関数です。インターフェイスのすべての機能が実装されている場合、この構造体はインターフェイスを実装します。一部の機能が実装されていない場合、実装は不完全になります。
Java では「implements」キーワードが必要ですが、Go では必要ないのはなぜですか? Go は完全にコンパイルされており、実行時にコンパイルされたコードを個別にロードする Java のようなクラス ローダーがないため、実際には Go は必要ありません。構造体がインターフェイスを実装するはずなのに実装していない場合、これはコンパイル時に検出されるため、インターフェイスがインターフェイスを実装しているかどうかを明示的に示す必要はありません。 Go のリフレクションを使用してこれを実装することもできますが、実行時エラーが発生しますが、いずれの場合も 'implements' キーワード宣言は効果がありません。
スレッドとキュー
Go 言語にはスレッドとキューが組み込まれています。それらはコルーチンとチャネルと呼ばれます。コルーチンを開始するには、別のスレッドで開始される go 関数 call() を記述するだけです。 Go の標準ライブラリには「オブジェクト」をロックするためのメソッドまたは関数がありますが、ネイティブ マルチスレッド プログラミングではチャネルが使用されます。チャネルは Go の組み込みタイプであり、他のタイプの固定サイズの先入れ先出しチャネルです。値をチャネルにプッシュし、コルーチンがチャネルから値をプルすることができます。チャネルがいっぱいの場合は押すとブロックされ、チャネルが空の場合は引くとブロックされます。
Go にはエラーはありますが例外はありません
Go には実際には例外処理がありますが、Java のように使用されるわけではありません。例外は「パニック」と呼ばれ、コード内に実際のパニックが発生した場合に使用されます。 Java ルールの観点から見ると、「パニック」は「...エラー」で終わるいくつかの例外に似ています。この状態は、処理可能な例外インスタンスまたはエラーが存在する場合にシステム コールによって返され、アプリケーション関数は同様のパターンでこの状態を処理することが期待されます。
finally はありません。defer が代わりに使用されます。
密結合例外処理は、Java が try/catch/finally 機能とともに実装する機能です。 Java では、最終ブロックに何があっても実行されるコードを置くことができます。 Go にはキーワード 'defer' が用意されており、メソッドが戻る前に (メソッドがパニックを起こした場合でも) 呼び出される関数を指定できます。 Defer を使用して上記の問題を解決すると、悪用されにくくなります。遅延関数呼び出しの後に実行可能コードを記述することはできません。しかし、Java では、finally ブロックに return ステートメントを記述したり、finally ブロックで実行されるコードを処理するために非常に紛らわしい try ステートメントが使用されたりすることもありますが、これも例外をスローする可能性があります。 Go は前者の傾向があります。
一般的に、Go は興味深い言語です。これは、言語レベルにおいても Java に代わるものではありません。 Java と Go は同じ種類のタスクを実行しません。Java はエンタープライズ レベルの開発言語であり、Go はシステム レベルのプログラミング言語です。
推奨の Java ビデオ チュートリアル: JAVA ビデオ チュートリアル
推奨の Go ビデオ チュートリアル: Go ビデオ チュートリアル
以上がphp を go または java に変換しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。