私は、自分のキャリアや興味に役立つ新しい言語を習得する旅の途中で、Go を試してみることにしました。今回は囲碁に挑戦してきました。第一印象としては、とても素敵だと思います。
これはガイド付きツアーではなく、個人的な思い出として私以外の誰かに向けて書かれたものではないでしょう。
私は、 Os-Release-Q という小さなプロジェクトを自分自身に与えました。私の目的は、自分が管理するどのシステムでもバイナリを保持できるようにして、解析したりアイグレップしたりすることなく、必要な情報を正確に出力できるようにすることでした。
Web を検索すると、他の人のパッケージのインポートについては多くのことが語られますが、自分自身のコードの編成についてはほとんど書かれていません。ドキュメントでも、懸念事項の分離ではなく、取得に焦点を当てています。
どの言語でも、このハードルにかなりの頻度で遭遇します。それぞれの言語には、どのように対処するか、また、それぞれにどのような制限があるか、課せられているかについて、独自の特異な哲学があるためです。
主に Python のバックグラウンドを持っている私が基礎を学ぶために取り組んだすべての活動の中で、コードを複数のファイルに分割することが、答えを得るまでに最も時間がかかった作業でした。要約すると、次のことがわかりました:
ローカル サブモジュールの場合、サブモジュールはフォルダー内に存在する必要があります。パッケージ 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 言語リファレンスがありました。
特に一般的な 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 が行うべきことを切り替えません。代わりに、位置指定が ["arg1", "arg2", "-flag"] として与えられます。解析されませんでした。
これは、ls -l が文字通り渡されるプログラム colorize ls -l のようなサブ呼び出しを渡すのに役立つ可能性があります。そのため、ユースケースがわかります。
ただ、世の中のほとんどのプログラムでは、位置項目の前後にフラグ引数を使用できるというだけです。 ls dir1/ -l dir2/ は ls -l dir1/ dir2/ と同じであり、これは Unix および Linux コマンドの大部分に適用される規則です。
これは慣れが必要なだけかもしれませんが、声をかける価値はあります。
ファイル インポート パラダイムはさておき、基本的なアプリケーションを実装するのは非常に簡単であることがわかりました。私が間違ったことはすべてかなり明白に感じられ、間違いには意味がありました。本当に「物事をやり遂げる」ことだけに集中できる気がします。
これまでのほんのわずかな使用量から、私の特定のニーズを考慮すると、次のことがわかります
オブジェクトや継承の代わりにスパース型を使用すると障害になると思いましたが、今のところは問題ありません。他の言語ではそれらがなくても大丈夫なので、インターフェイスと型を定義するようになると、Lua や bash からのステップアップのように感じるでしょう。願っています。
私がネイティブにコンパイルされる言語を検討したいと思った理由の 1 つは、存在するランタイムの特定のバージョンに依存することなく、簡単に迂回できるバイナリを生成できることでした。
最近、同僚が落胆しながら私のデスクにやって来て、Debian 10 をベースにした古い Node ベース イメージに Java 17 をインストールする問題を解決しようとしていました。 Node のバージョンをアップグレードして新しいベース イメージを取得するか、新しい Debian ベース イメージを使用して Node を手動でインストールして構成するか、インターネットを検索して善意の人がホストするカスタム リポジトリを探して善意の人を探す必要があります。 -ハッキングされた場合、Debian 10 上で動作する Java 17。
デプロイされたソフトウェアにそのような競合するランタイム依存関係がなければ、どれほど簡単になるでしょうか...
運用の観点から、私が感じている大きなメリットは、コードを簡単に記述して ELF バイナリをビルドして「任意のシステム X」にデプロイできるため、競合する必要がないことです。特定のランタイムの正しいバージョンが配置されていることを確認し、競合する依存関係を管理します。
他にも利点があると確信しています。Go でのマルチスレッドとマルチプロセッシングの使いやすさについてはよく言われているので、次のステップとしてそれを探求するミニ プロジェクトを作成するつもりです。おそらく、複数のチャネルで入力をリッスンし、それに応じていくつかの基本的なタスクを実行するものでしょう。以前にいくつかのテスト自動化タスクでその使用例があったため、現時点では私にとって無縁ではありません。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3