ホームページ  >  記事  >  バックエンド開発  >  Go でベイビーステップ

Go でベイビーステップ

WBOY
WBOYオリジナル
2024-08-05 19:28:13380ブラウズ

Baby steps with Go

私は、自分のキャリアや興味に役立つ新しい言語を習得する旅の途中で、Go を試してみることにしました。今回は囲碁に挑戦してきました。第一印象としては、かなり素敵だと思います。

これはガイド付きツアーではなく、個人的な思い出として私以外の誰かに向けて書かれたものではないでしょう。

私は、 Os-Release-Q という小さなプロジェクトを自分自身に与えました。私の目的は、私が管理するどのシステムでもバイナリを保持できるようにして、解析やアイグレップを必要とせずに、必要な情報を正確に出力できるようにすることでした。

最初のハードル: インポート

Web を検索すると、他の人のパッケージのインポートについては多くのことが語られますが、自分自身のコードの編成についてはほとんど書かれていません。ドキュメントでも、懸念事項の分離ではなく、取得に重点を置いています。

どの言語でも、このハードルにかなりの頻度で遭遇します。それぞれの言語には、どのように対処するか、また、それぞれにどのような制限があるか、課せられているかについて、独自の哲学があるためです。

主に Python のバックグラウンドを持っている私が基礎を学ぶために取り組んだすべての活動の中で、コードを複数のファイルに分割することが、答えを得るまでに最も時間がかかった作業でした。要約すると、次のことがわかりました:

  • トップレベルにはモジュール module-name を宣言する go.mod が必要です
  • その後、トップレベルに src/ ディレクトリを設定し、 main 関数を配置する src/main.go を設定し、パッケージの main 宣言を最上位に設定します
  • 他のファイルにコードを配置するのは、パッケージのメイン宣言を含む src/others.go のようなファイルを作成するだけで簡単です。
  • すべての関数と変数は、パッケージ main の他のファイルで直接使用できるようになりますが、ファイルは go build FILES 呼び出しで明示的に指定する必要があります

ローカル サブモジュールの場合、サブモジュールはフォルダー内に存在する必要があります。パッケージ submodule-name を宣言できます。

それが src/submod/ にあり、メインの実装者が src/submod/submod.go にあるとします。 main.go では、「module-name/src/submod」をインポートします (go.mod から取得した module-name を使用)。そして、submod.SomeFunction().

を呼び出すことができます。

サブモジュール関数は、名前が大文字で始まる輸入者のみが使用できることに注意してください。したがって、submod.myFunction() は実行できません。submod.MyFunction() でなければなりません。

サブモジュールとインポートに関しては他にも考慮すべき点があることは確かですが、コードを整理して分離しておくという点では、これが重要です。

物事を正常に保つために、パッケージ main を宣言するファイルを 1 つだけにして、残りをサブモジュールに分離するようにしました。これらは、go build ファイルの FILES リストで宣言する必要がなく、自動的にインポートされます。

基本的なタスクを実行する

Go のこの特殊性を解決したら、残りの部分は非常に簡単に収まりました。すべての基本タスクには、もちろん StackOverflow エントリ、または GoByExample.com ページ、そしてより基本的には Go 言語リファレンスがありました。

  • 文字列の処理は strings パッケージを介して行われます
  • 配列処理には、base_array = append(base_array, item1, item2) パターンなどのネイティブ関数が多数あります。この関数は、append(base, other_array...) を介して別の配列の値を使用して配列を拡張する場合にも機能します。
  • エラー処理は通常、エラー オブジェクトを渡すことによって行われますが、必ずしもそうである必要はありません。
  • 「ログ」ライブラリは、事前設定された便利な非フェージングログ用に存在します。これには、エラーをログに記録し、すぐに終了する log.Fatal(message) 呼び出しが含まれています。
  • サブプロセスの呼び出しは、exec.Command(base, args...) パターンを使用して、「os/exec」ライブラリ経由で簡単に行えます

特に一般的な 2 つのタスクについては、それぞれの段落に分けて説明します。

エラー処理

基本的なエラー処理は、文字通り制御フローの途中でエラーを処理する必要があり、面倒であるとコメントされることがよくあります。これは、try/catch ワークフローを使用するプログラマにとっては忌まわしいことかもしれませんが、問題が発生する可能性がある時点で問題に対処することは、それほど悪いことではありません。

// explicit return item `err` forces us to be aware of it
// but having the ability to check it in the same breath is not so bad
if result, err := someCall(); err != nil {
    log.Fatal("Sorry.")
}

// Equally valid is
/*
result, err := someCall()
if err != nil {
    log.Fatal("Sorry")
}
*/

fmt.Println(result)

トライ/キャッチ方法を比較

try:
    result = someCall()
    print(result)
except:
    print("Sorry") # a little divorced from potential origin of error
    sys.exit(1)

引数の解析

フラグライブラリの実装がちょっと中途半端な気がしてなりません。現在の形で生き残っていることを考えると、明らかに人々はそれに慣れており、問題なく受け入れています。

program -flag arg1 arg2 を呼び出すと、フラグが実行するように設定されている切り替えが行われ、positionals := flags.Args() が ["arg1", "arg2"] の配列を返します

ただし、プログラム arg1 arg2 -flag を呼び出しても、-flags が行うことを切り替えせず、代わりに is 位置指定が ["arg1", "arg2", "-flag"] として与えられます。解析されませんでした。

これは、ls -l が文字通りに渡されるプログラム colorize ls -l のようなサブ呼び出しを渡すのに役立つ可能性があります。そのため、ユースケースを確認できます。

世にあるほとんどのプログラムでは、位置項目の前後にフラグ引数を使用できるというだけです。 ls dir1/ -l dir2/ は ls -l dir1/ dir2/ と同じであり、これは Unix および Linux コマンドの大部分に適用される規則です。

これは慣れが必要なだけかもしれませんが、声をかける価値はあります。

Goの目的とユースケース

ファイル インポート パラダイムはさておき、基本的なアプリケーションを実装するのは非常に簡単であることがわかりました。私が間違ったことはすべてかなり明白に感じられ、間違いには意味がありました。本当に「物事を成し遂げる」ことだけに集中できるようになった気がします。

これまでの私の使用量が非常に少ないことから、私の特定のニーズを考慮すると、次のことがわかります

  • 簡単に始められます
  • コンパイル済みバイナリ、ランタイム依存関係なし
  • 型を使用した単純な言語は、シェル スクリプトからのステップアップです
  • 簡単なマルチプロセッシングのサポートとされています

オブジェクトや継承の代わりにスパース型を使用すると障害になると思いましたが、今のところは問題ありません。他の言語ではそれらがなくても大丈夫なので、インターフェイスと型を定義するようになると、Lua や bash からのステップアップのように感じるでしょう。願っています。

私がコンパイルされてネイティブに変換される言語を検討したいと思った理由の 1 つは、存在するランタイムの特定のバージョンに依存することなく、簡単に迂回できるバイナリを生成できることでした。

最近、同僚が落胆しながら私のデスクにやって来て、Debian 10 をベースにした古い Node ベース イメージに Java 17 をインストールする問題を解決しようとしていました。 Node のバージョンをアップグレードして新しいベース イメージを取得するか、新しい Debian ベース イメージを使用して Node を手動でインストールして構成するか、インターネットを検索して善意の人がホストするカスタム リポジトリを探して善意の人を探す必要があります。 -ハッキングされた場合、Debian 10 上で動作する Java 17。

デプロイされたソフトウェアにそのような競合するランタイム依存関係がなければ、どれほど簡単になるでしょうか...

運用の観点から、私が感じている大きなメリットは、コードを簡単に記述して ELF バイナリをビルドして「任意のシステム X」にデプロイできるため、競合する必要がないことです。特定のランタイムの正しいバージョンが配置されていることを確認し、競合する依存関係を管理します。

他にもメリットがあると思います。Go でのマルチスレッドとマルチプロセッシングの使いやすさについてはよく言われているので、次のステップとしてそれを探求するミニプロジェクトを作成するつもりです -おそらく、複数のチャネルで入力をリッスンし、それに応じていくつかの基本的なタスクを実行するものでしょう。以前にいくつかのテスト自動化タスクでその使用例があったため、現時点では私にとって無縁ではありません。

以上がGo でベイビーステップの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。