Open10

実用Go言語のメモ

ganezasanganezasan

Goを利用するための上司の説得方法まとめ

  • 学びやすい
  • 実装の効率が高いのにパフォーマンスが高い
  • Goはクラウドネイティブ言語(クロスコンパイルが得意、Go対応のSDKも豊富)
ganezasanganezasan

第1章「Goらしさ」に触れる

Goの命名について公式見解があり、Effective Goに従うのがGoらしいコードだと言える。

Namesのパートがある。
https://go.dev/doc/effective_go#names

1.1.1 変数名

変数名が複数の単語で構成されるとき、_(アンダースコア)を使用せず、MixedCapsとする慣習となっている。
max_length → maxLength

他のパッケージから参照できる公開された変数は、先頭を大文字とする
先頭が小文字の変数は非公開

URLやID、HTTP、APIのような頭字語(acronym)はUrlやIdとせずにURL、IDもしくはurl、idとする
他の単語と頭字語を組み合わせる場合は大文字を使う。ServeHTTP、stackIDなど

エラーの変数名は接尾語Errorを付ける
MarshalerError
UnsupportedTypeError
jsonError

errors.New("my error")と宣言されるようなエラーの変数はErrまたはerrから始まる
ErrTooLong = errors.New("")
ErrNegativeAdvance = errors.New("")
ErrAdvanceTooFar = errors.New("")

グローバル変数にはわかりやすい名前を、ローカル変数には短い名前をという考え方がGoでは一般的

ganezasanganezasan

1.1.2 パッケージ名

priority_queueのようなスネークケースやArrayListのようなキャメルケースを用いたパッケージ名はGoらしくない。複数の名刺で構成したくなった場合はフォルダを分ける。

例外として、テストに用いるパッケージはパッケージ名+_testという名前をもちいることがある。
パッケージ名と関数名に重複があるのは冗長だとされる。

  • http.Serverであってhttp.HTTPServerではない
  • zip.NewWriterであってzip.NewZipWriterではない
ganezasanganezasan

1.1.4 レシーバー名

1文字または2文字であわらすのが普通

Requestであればr、Regexpであればre。JavaのthisやPythonのselfのような名前は利用しない。

ganezasanganezasan

1.2.1 型のない定数を定義する

定数とリテラルはほぼイコール。演算を定数に埋め込んだ場合、コンパイル時に計算の答えがバイナリに埋め込まれるため、計算コストは0になる。

代入されたり、型が指定されるまでは型が決定されず、数値型であれば値の範囲に限界はない。正確には521ビットの限界はある。

型を付与せずにconstキーワードを使うと、定数に名前をつけられる。名前の後ろに型名をつけてなければ、定数のままで型がない状態。

const (
 a = 1
 e = iota +10
)

1.2.2 型付きconst変数を定義する

type ErrorCode int
const (
 f int = 10
 code ErrorCode = 10
)

1.2.3 多言語との違い

Goのconstはコンパイル時に決定される不変の値にしか利用できない
なので、複合型(配列やスライス、マップ、関数の返値)に対しては利用できない。

C++ではconstは構造体やクラスなどの複合型で「属性値の変更を許さない」
JavaScript/TypeScriptではconstは「変数の再代入を許さない」という意味に限定している

JavaScriptとTypeScriptはオブジェクトや配列はconst変数に格納し、また値を書き換えが可能。
Goでは複合型はvarにしか格納できない

ganezasanganezasan

Goはフレームワーク実装者向けの「ヤンチャできないように徹底的に縛る」ための機能はあまり提供されていない。Goからは後ろ向きの努力に手間をかけず開発者を信じて性善説で行く、という姿勢を感じる。

ganezasanganezasan

1.3 iotaを用いて列挙型を実現する

Goにはenumキーワードなどはありませんが、次の要素を句合わせて列挙型に近い機能を実現できる。

  • 種別を表す型をtypeキーワードで作成
  • 定数のリストをconstで作成
  • 定数に割り当てる値としてiotaを利用
type CarType int

const (
  Sedan CarType = iota + 1
  Hatchback
  MPV
  SUV
)

var t CarType
t = SUV

iotaの初期値は0ですが、初期化されていない状態の0と最初の要素となる0を区別するため、サンプルのように+1して、1オリジンにするのが一般的。

ganezasanganezasan

1.3.5 文字列として出力可能にする

intをベースにした列挙型は、ログなどに出力すると元となった整数値が出力される。Goの準標準ライブラリstringerコマンドを使って整数値を文字列に変換するコードを生成することで解決できる

列挙型風の定数を定義sちえいるファイルに次のようにコメント表を書く

//go:generate stringer -type=CarOption
//go:generate stringer -type=CarType

もしくはenumerでも可能

ganezasanganezasan

1.4 Goのエラーを扱う
1.4.4 他の言語との違い

Goは例外機構が存在しないかわりに、エラーが発生し得る場合は関数からの戻り値を使ってエラーを処理する。

ganezasanganezasan

1.5 変数は短縮形式:=とvarのどちらを使うべきか?

基本的には短縮形式を利用する

var empty string
one :=  1

型を明示する

var three int8 = 3
four := int16(4)