要約: この記事は元々、Grape City の技術チームによって CSDN に公開されたものです。転載元を明記してください:グレープシティ公式ウェブサイト、グレープシティは、開発者に力を与えるための専門的な開発ツール、ソリューション、サービスを開発者に提供します。
序文
Go 言語と C# 言語との比較をより深く紹介するために、この記事では多面的に詳しく説明します。まず、Go 言語のキーワードの観点から Go と C# の類似点と相違点を紹介し、キーワードの観点から 2 つの言語の最適化と欠点について説明します。次に、この記事ではコード例やパフォーマンス テストなどを通じて、キーワードに関する Go 言語の利点を示し、Go 言語の威力を読者に示します。さらに、読者が Go 言語をよりよく理解できるように、この記事では、読者がさらに学習して探索するための優れた Go 言語ツールとコミュニティ リソースも紹介します。これらの内容を総合的に紹介することで、読者の皆様には Go 言語についてより包括的かつ深く理解していただけるものと信じています。
記事ディレクトリ:
1.1 Go言語の誕生過程
1.2 ステップバイステップの成形
1.3 正式リリース
1.4 Go インストール ガイド
2.1.2 . スイッチケースのデフォルト
2.1.3.If -else
2.1.4 . ために
2.1.5 . 構造体
2.2Go と C# で同じではないが、同様の意味を持つキーワード
2.2.1 . パッケージと名前空間
2.2.2 . インポートと使用
2.2.3 . 型とクラス
2.2.4 . 延期して最後に
2.3Go には あるが C# にはないキーワード
2.3.1 . フォールスルー
1. 囲碁の過去と現在
1.1 Go言語の誕生過程
2007 年 9 月のある日、Google エンジニアのロブ・パイク氏はいつものように C++ プロジェクトの構築を開始したと言われていますが、これまでの経験によれば、この構築には 1 時間ほどかかるはずです。この時、彼と他の 2 人の Google 同僚、ケン トンプソンとロバート グリーズマーは不平を言い始め、新しい言語についてのアイデアを表明しました。当時、Google は社内でさまざまなシステムを構築するために主に C++ を使用していましたが、C++ の複雑さと並行性のネイティブ サポートの欠如により、3 つの大きな上司は非常に悩みました。
初日の雑談は有意義で、プログラマに喜びをもたらし、将来のハードウェア開発トレンドに適合し、Google 社内の大規模ネットワーク サービスを満足させる新しい言語をすぐに思いつきました。そして二日目に彼らは再び集まり、新しい言語について真剣に考え始めました。翌日の会議の後、ロバート・グリーズマーは次のような電子メールを送信しました。
電子メールから、この新しい言語に対する彼らの期待は次のとおりであることがわかります。 **C 言語をベースにして、いくつかのエラーを修正し、いくつかの批判された機能を削除し、いくつかの不足している機能を追加します。**Switch ステートメントの修復、import ステートメントの追加、ガベージ コレクションの追加、インターフェイスのサポートなど。そして、このメールが Go の設計の最初の草案となりました。
この数日後、ロブ・パイクは車で帰宅する途中、新しい言語に Go という名前を思いつきました。彼の頭の中では、「Go」という単語は短く、入力しやすく、Go のツールチェーン (goc コンパイラー、goa アセンブラ、gol リンカーなど) など、その後の他の文字と簡単に組み合わせることができます。また、この単語は彼らの言葉にも適合します。言語設計の本来の意図: シンプル。
1.2 ステップバイステップの成形
Go の設計思想を統一した後、Go 言語は言語の設計の反復と実装を正式に開始しました。2008 年に、C 言語の父である Ken Thompson が Go コンパイラの最初のバージョンを実装しました。このバージョンの Go コンパイラは今でも C 言語で開発されています。その主な動作原理は、Go を C にコンパイルしてからコンパイルすることです。 C をバイナリに変換します。2008 年半ばまでに、Go の設計の最初のバージョンはほぼ完成しました。このとき、同じく Google で働いていた Ian Lance Taylor は、Go 言語の 2 番目のコンパイラでもある Go 言語用の gcc フロントエンドを実装しました。イアン・テイラーのこの功績は励ましであるだけでなく、新しい言語である Go の実現可能性の証明でもあります。言語の 2 番目の実装では、Go の言語仕様と標準ライブラリを確立することも重要です。その後、Ian Taylor は Go 言語開発チームの 4 人目のメンバーとして正式に加わり、後に Go 言語の設計と実装における中心人物の 1 人になりました。Russ Cox は Go コア開発チームの 5 人目のメンバーで、これも 2008 年に加わりました。チームに参加した後、Ross Cox は、関数型が「第一級市民」であり、独自のメソッドを持つこともできるという特徴を利用して、http パッケージの HandlerFunc 型を巧みに設計しました。このようにして、明示的な変換を通じて、通常の関数を http.Handler インターフェイスを満たす型にすることができます。それだけでなく、Ross Cox は、Go 言語の I/O 構造モデルを確立した io.Reader インターフェイスや io.Writer インターフェイスなど、当時の設計に基づいたより一般的なアイデアも提案しました。その後、Ross Cox は Go コア技術チームの責任者となり、Go 言語の継続的な進化を推進しました。この時点で、Go 言語の初期コアチームが形成され、Go 言語は安定した進化の道を歩み始めました。
1.3が正式リリースされました
2009 年 10 月 30 日、Rob Parker は Google Techtalk で Go 言語に関する講演を行い、これが Go 言語が初めて公開されました。10 日後の 2009 年 11 月 10 日、Google は Go 言語プロジェクトがオープンソースであることを正式に発表し、この日が Go によって Go 言語の誕生の日として正式に指定されました。
1.4. Go インストールガイド
1. Go言語インストールパッケージのダウンロード
Go公式サイト:https://golang.google.cn/
対応するインストール バージョンを選択するだけです (.msi ファイルを選択することをお勧めします)。
2. インストールが成功したかどうか、および環境が正常に構成されているかを確認します。
コマンド ラインを開きます: win + R を押して実行ボックスを開き、cmd コマンドを入力してコマンド ライン ウィンドウを開きます。
コマンドラインに go version と入力するとインストールされているバージョンが表示され、以下の内容が表示されればインストール成功です。
2. Go と C# のキーワード比較
Go には 25 のキーワードがありますが、C# には 119 のキーワードがあります (77 の基本キーワードと 42 のコンテキスト キーワードを含む)。量だけで言えば、C# の数は Go の 5 倍であり、これが Go が C# より簡単である理由の 1 つです。
Go の 25 のキーワード:
壊す | デフォルト | 機能 | インターフェース | 選択する |
---|---|---|---|---|
場合 | 延期する | 行く | 地図 | 構造体 |
ちゃん | それ以外 | 後藤 | パッケージ | スイッチ |
定数 | フォールスルー | もしも | 範囲 | タイプ |
続く | ために | 輸入 | 戻る | だった |
2.1 Go と C# の両方のキーワード
- 壊す
- 場合
- 定数
- 続く
- デフォルト
- それ以外
- ために
- 後藤
- もしも
- インターフェース
- 戻る
- 構造体
- スイッチ
- だった
上記 14 個のキーワードは Go と C# で共通であり、ほとんどがまったく同じように使用されますが、ここでは Go の特殊な構文を持つキーワードに焦点を当てます。
2.1.1. 変数
Go では Var を使用して変数を定義しますが、構文は C# とは異なります。C# では変数を定義する方法は 1 つしかありませんが、Go では次の 2 つの方法があります。
- 通常の方法
var i int = 1
この方法はGo独自の変数定義方法で、一般的にパッケージレベルの変数はこの方法で定義されており、上記の例のようにコンパイラが自動的に推論できる型を定義しておけば、それ以降の型を省略することができます。
- 糖衣構文 (はい、Go にも糖衣構文があります...)
i, j := 1, "hello"
上記のコードは、構文シュガーと略すことができます。実際、Go コードの変数の 90% はこの方法で定義されています。これは、ほとんどすべての関数が複数の戻り値を持ち、この方法で定義すると多くの問題を回避できるためです。
2.1.2.Switch-case-default
switch-caseは組み合わせて使えるメソッドですが、Goではswitch以外にcaseとdefaultの2つのキーワードをselect文と組み合わせて使うことができます。
同時に、Go は switch 文の欠点をデフォルトで修正します。つまり、switch 句に Break を記述する必要がありません。
switch n := "a"; n {
case n == "a":
fmt.Println("a")
case n == "b":
fmt.Println("b")
case n == "c":
fmt.Println("c")
}
上記のコードの fmt は Go の標準出力パッケージであり、Println 関数は C# の Console.WriteLine メソッドに相当します。同時に、このコードの最終結果は a のみを出力しますが、C# では同じコードはすべて abc を出力します。これが、Go が C# よりも単純である理由の 1 つです。
さらに、新しい書き方が switch ステートメントの後ろに表示されます: n := "a"; n、この書き方は Go の制御ステートメント (if、else if、switch-case、for) で使用できます。セミコロンは変数の定義、セミコロン以降は判定条件の定義です。この構文上の利点は、C# の通常の for ループの最初の 2 つの句に似ています。
最後に、スイッチの後に括弧がないことがわかります。これは、Go では制御ブロックの句の後に括弧が必要なく、括弧が書かれていれば、gofmt によって自動的に整形されるためです。
2.1.3. If-else
Go の if-else は C# とほぼ同じです。両者の最大の違いは、Go の特別な構文です。if-else 制御ブロック内の変数に値を直接代入し、これらの値を C# で使用できます。コントロールブロック。
func isEven(n int) bool {
return n % 2 == 0
}
func main() {
if n := rand.Intn(1000); isEven(n) {
fmt.Printf("%d是偶数\\n", n)
} else {
fmt.Printf("%d是奇数\\n", n)
}
}
2.1.4. ために
Go のループ制御ステートメントには、for キーワードが 1 つだけあります。C# の while と foreach はすべて、Go の for のさまざまなバリエーションを通じて実現されます。
- while ステートメント
for true {
// ...
}
- for ステートメント
for i := 0; i < n; i++ {
// ...
}
Go と C# の通常の for ループの唯一の違いは、i++ が式からステートメントに変わったことです。つまり、Go には i = i++ のような構文はなく、++i のような構文も存在せず、i++ のみです。
- foreach ステートメント
array := [5]int{
1, 2, 3, 4, 5}
for index, value := range array {
// ...
}
foreach ステートメントの記述方法は、C# の記述方法とは大きく異なります。上記の例では、foreach は int 型の配列を走査し、その中で range キーワードが使用されています。このキーワードは、配列を 2 つの反復サブオブジェクト インデックスに分割します。および値、for range は、配列、スライス、文字列、マップ、およびチャネル (チャネル) をトラバースできます。この構文は、JavaScript のループ構文にも似ています。たとえば、次のコードは配列内の値を走査して出力します。
for key, value := range []int{
1, 2, 3, 4} {
fmt.Printf("key:%d value:%d\\n", key, value)
}
コード出力は次のとおりです。
key:0 value:1
key:1 value:2
key:2 value:3
key:3 value:4
2.1.5 構造体
Go の struct キーワードには、C# と同じ機能、つまり構造体を定義します。Go にはクラスの概念がないため、struct は C# のクラス定義に相当します。同様に、 Go ではstruct も値型の構造体なので、使用する場合は値の転送によるコピー問題に注意する必要があります。( Go の struct はフィールドのみを定義でき、関数は定義できないことに注意してください。)
// struct的定义是配合type关键字一起使用的
type People struct {
name string // 定义的字段和Go语言其他的风格相同,名字在前,类型在后
age int
}
2.2Go と C# で異なるが、同様の方法で使用されるキーワード
2.2.1.パッケージと名前空間
Go のパッケージは基本的に C# の名前空間と同じで、組織を定義するパッケージであり、その主な機能はコード モジュールを分離することです。ただし、Go と C# の違いは、C# は非常に柔軟であり、同じフォルダーにないコードでも同じ名前空間として定義できることです。ただし、Go のパッケージ内のファイルは正しくコンパイルされるために同じフォルダーにある必要があり、フォルダー内に表示できるパッケージ名は 1 つだけです。また、C# の Main メソッドと同様、Go の実行可能プログラムの実行エントリも main 関数ですが、main 関数は main パッケージの下に定義する必要があります。
// Go中,同一个文件夹只能同时存在一个包名
// 包名可以和文件夹名不同,但是必须有且只有一个
package main
// main函数只能在main包下才能正确作为启动函数运行
func main() {
//do something
}
// 同文件夹下的另一个文件,比如hello.go
package hello //编译器报错
2.2.2.インポートと使用
Import と using の両方は、他のモジュールからコードをインポートするために使用されます。ただし、Go には C# よりも必須の要件が 1 つあります。コード モジュールで import を使用しない場合、または変数を定義しても使用されない場合、コンパイル時にエラーが直接報告されます。この主な理由は、コードがより簡潔に見えることに加えて、import ステートメントには、パッケージ内の init() 関数を呼び出すという別の重要な機能があるためです。たとえば、次のコード:
// hello文件夹下的demo文件夹内的 demo.go
package demo
var me string
func init() {
me = "jeffery"
}
func SayHello() {
fmt.Printf("hello, %s", me)
}
// hello文件夹下的hello.go
package main
import "hello/demo"
func main() {
demo.SayHello() // 输出:hello, jeffery
}
上記のプログラムはデモ ファイルを定義しています。このデモ ファイルが import キーワードによって他のパッケージに初めてロードされるとき、その init() 関数が自動的に呼び出されます。このとき、変数 me には jeffery が代入されます。その後、SayHello() 関数が呼び出され、「こんにちは、ジェフリー」が返されます。init 関数が存在するからこそ、未使用のインポートを削除する必要があります。削除しないと、未使用のパッケージ内の init 関数が自動的に呼び出される可能性があるためです。
2.2.3. タイプとクラス
- 従来の使用法
型とクラスを比較することは合理的ではありません。C# の class キーワードは、型とその型の特定の実装を定義することであるため、たとえば、C# の次のコードは、People という名前のクラスを定義し、このクラスに属性 Age を定義することを意味します。
interface IAnimal {
public void Move();
}
class People {
public int Age {
get;set; }
}
ただし、Go の type キーワードは型名の定義にのみ使用されるため、その実装を定義したい場合は、後で特定の実装キーワードを追加する必要があります。たとえば、上記のコード定義は Go では次のようになります。
type IAnimal interface {
Move()
}
type People struct {
Age int
}
上記は type の最も一般的な使用法にすぎません。type に加えて、他にも 2 つの使用法があります。
- 基本型に基づいて新しい型を定義する
type Human People
このようなステートメントは、People タイプを使用して新しいタイプの Human を定義することと同じです。これは新しい型であり、 C# の継承ではないことに注意してください。したがって、People に Move 関数がある場合、Human オブジェクトはこの Move 関数を呼び出すことができないため、使用する必要がある場合はキャストする必要があります。(Go で必須の型変換は type + () です。たとえば、上記の例のように Human(People) は People 型を Human 型に強制できます)
- 型の別名を定義する
type Human = People
等号を使用して定義すると、People 型に対してエイリアス Human を定義することと同じになり、この場合、People の Human というコードも通常どおりに使用できます。上記 2 つの用法は基本的に一般的には使用されないため、ここでのみ理解する必要があります。
2.2.4.延期して最後に
Go の defer は C# のfinally と同じで、メソッドが終了する前に実行できることは 1 つだけです。C# とは異なり、Go では defer ステートメントを最後に記述する必要がありません。たとえば、次のようなスタイルのコードがよく見られます。
var mutex sync.Mutex // 一个全局锁,可以类似的等价于C#中的Monitor类
func do() {
mutex.Lock()
defer mutex.Unlock()
// ...
}
上記の例は、グローバル ロックを定義し、 do 関数が入ったときにロックし、終了したときにロックを解除することを意味します。次に、独自のビジネス ロジックを作成します。さらに、複数の遅延を記述することもできますが、最終的な実行順序は下から上に実行されます。つまり、最後に定義された遅延が最初に実行されます。
2.3Go にはあるが C# にはないキーワード
2.3.1. フォールスルー
このキーワードは、C 言語のフォールスルーとの互換性を保つためのもので、その目的は、次の例のように、switch-case ステートメントの case にジャンプすることです。
switch n := "a"; n {
case n == "a":
fmt.Println("a")
fallthrough
case n == "b":
fmt.Println("b")
case n == "c":
fmt.Println("c")
}
この例の最終出力は次のようになります。
a
b
### 2.3.2.機能
他の関数 (JavaScript の function、Python の def など) と同様に、Go の func は関数を定義するために使用されます。
// 定义了一个函数名称为getName的函数
// 其中包含一个int类型的参数id
// 以及两个返回值,string和bool类型
func getName(id int) (string, bool) {
return "jeffery", true
}
Go の関数や型定義を必要とするその他の一連の構文では、名前は常に type の後に続きます。さらに、Go の func を type とともに使用して、C# でデリゲートを定義することもできます。たとえば、C# で .Net Core ミドルウェアを定義できます。
public delegate void handleFunc(HttpContext httpContext);
public delegate handleFunc middleware(handleFunc next);
このようなコードは次のように Go で実装できます。
type handleFunc func(httpContext HttpContext)
type middleware func(next handleFunc) handleFunc
3. 拡張リンク
Blazor フレームワークを使用してフロントエンド ブラウザーで Excel XLSX をインポート/エクスポートする方法