導入
こんにちは、もんすんです。
皆さんはGo言語、使ったことがありますか?
私は、いつか触ろう触ろうと考えていたのですが、タイミングを見失っていました。
今回、2024年のアドベントカレンダーを進める上で、やっと機会が生まれたので、触ることにしました。
Goについて
Go言語は、2019年11月にGoogleによって発表されたプログラミング言語です。
特徴
Go言語には以下のような特徴があります。
- シンプルな言語設計・文法
- 並行処理
- 標準ライブラリ群が豊富
- クロスコンパイル
などなど。
シンプルな言語設計・文法
各機能が重複するような部分を排除した設計になっています。
例えば、繰り返し処理はfor文のみで、while文はありません。
プロジェクトごとの独自ルールを設定したり、その学習コストがかかったりすることを避けるためにこのような設計になっているそうです。
並行処理
goroutine
という軽量なスレッドが、ランタイムで管理されており、各goroutine
はメモリを共有することで、1つの変数に対して複数のgoroutine
からアクセスすることが可能になっています。
goroutine
間でのデータの競合が発生しないようにchannel
という機能が利用されています。
これらによりGoの高パフォーマンスを実現しています。
標準ライブラリ群が豊富
100以上の標準パッケージがあります。
サードパーティライブラリを探す前にまず、標準ライブラリに該当するものがないかは確認することが重要な気がします。
また、標準だけでなく、準標準と呼ばれるライブラリ群も用意されているようです。
golang.org/x
以下のライブラリがそれに該当します。
これらは、十分な検証の末、標準ライブラリに転身する可能性があるライブラリ群になっており、標準ライブラリで実現したいものがなかった場合に確認すべきライブラリ群といえます。
クロスコンパイル
開発マシンと異なるOSで動作可能な実行ファイルを生成できるらしいです。
触ってみた
早速触っていきます。
今回はVSCodeのdevcontainerを利用しています。
イメージは以下の通り。
"image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm",
- Goのバージョン
go version
# go version go1.23.2 linux/amd64
標準出力
まずは、確認のため、以下のコードで、標準出力を試します。
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World!")
}
今回はfmt
パッケージを使用して、標準出力を行いました。
こんな感じで正しく出力することができました。
println
とfmt.Println
の違い
Go言語での標準出力には、println
とfmt.Println
があります。
これらにはいくつかの違いがあります。
println
-
基本的な標準出力
- Go言語に組み込まれている低レベルのデバッグ用の関数
-
fmt
パッケージをインポートせずに使用可能 - 書式指定や高度な出力はできない
-
用途
- 主にデバッグ目的で使われることが想定されており、正式なコードでは推奨されない
-
出力のフォーマット
- 自動的にスペースで引数を区切って出力しますが、厳密に定義されたフォーマットが保証されていません
-
使用例
func main() {
println("Hello, World!")
println("Number:", 42)
}
-
注意点
- 実行環境によって動作が異なる可能性があるため、移植性が低い
- エラー処理やフォーマットが不要なシンプルなケース以外では、通常使用しません
fmt.Println
-
高機能な標準出力
-
fmt
パッケージが提供する関数で、書式付きの出力が可能 - より堅牢で移植性があり、実際のアプリケーションコードで推奨される
-
-
用途
- フォーマット付きの出力や、信頼性の高いログ出力に使用される
-
出力のフォーマット
- 自動的にスペースで区切られた引数を出力し、最後に改行が付加されます
- フォーマットの制御には、
fmt.Printf
などと組み合わせて柔軟な制御が可能
-
使用例
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World!")
fmt.Println("Number:", 42)
}
-
特徴
- 型に基づく適切な出力を提供
- 他の
fmt
パッケージの関数(Printf
,Sprintf
など)と一貫性がある
主な違いのまとめ
特徴 | println |
fmt.Println |
---|---|---|
場所 | 組み込み関数 |
fmt パッケージに属する |
目的 | デバッグ専用で非推奨 | 通常の出力に適している |
フォーマット | 単純で曖昧なフォーマット | 一貫性のあるフォーマット |
移植性 | 低い | 高い |
拡張性 | なし | 高い(Printf なども利用可能) |
推奨
一般的なコードでは、移植性や拡張性が高いfmt.Println
を使うのが良さそうです。
println
は単純なデバッグ以外では避けるべきとされています。
Effective Go
さて、標準出力ができたのですが、Goの作法はよくわかりません。
ですが、実はそれを体系的にまとめているサイトがあります。
それが、Effective Goです。助かる。
また、それを翻訳しているサイトもあるみたいでした。
Effective Go — プログラミング言語 Go ドキュメント v0.1 documentation
通常のコーディングルールだけでなく、上記で少し触れたgoroutine
やchannel
についても書かれているので、取り組む前にざっと目を通しておくのが良さそうです。
私がサラッと読んで目に留まったのは以下の点です。
- パッケージ名はできるだけ短くする
- containerVectorとかにするのではなく、cotainer/vectorのように極力1つ1つを短くするということ
- インターフェース名は、サフィックスとして
er
をつけて表現する- 例: ReadメソッドのIF名はReader
- 変数の宣言のみの場合は型定義が可能
- 例:
var x int
- 一方、宣言と初期化を同時に行う場合は
:=
を利用し、型定義は不要になる- 例:
x := 10
- 例:
- 例:
- for文やif文の
( )
が不要- 例:
for i := 0; i < 10; i++ {}
- 例:
終わりに
いかがでしたでしょうか?
今回はGo言語の基本的な特徴から始まり、標準出力やコーディングスタイルに触れてみました。
Goはそのシンプルさやパフォーマンス、そして豊富な標準ライブラリが魅力であり、これから学ぶ上でその強みを最大限に活かしたいと思います。