Goの勉強 パッケージとGoツール

Goの勉強をやり始めたのでメモ。
プログラミング言語 Go」を読んでる。

  • Goではパッケージが導入されていて、パッケージを通して再利用可能になっている。
  • 公開されたパッケージは http://godoc.org で確認できる。

導入

  • パッケージの目的は、他のパッケージとは独立に、関連する機能を、変更や理解が容易にできる単位にまとめることである。
    • モジュール性という。
  • 個々のパッケージは独自の名前空間を定義するため、他のパッケージの名前と衝突しない。
  • パッケージは可視性を利用してカプセル化を提供する。
  • ファイルを変更すると、そのファイルの含まれるパッケージ全体を再コンパイルしないといけない。
  • Goのコンパイラは他の言語のコンパイラよりも速い
    • import文が先頭にあることで、ファイルをすべて読み込まなくても依存関係がわかるため。
    • 循環がないため並列にコンパイルできるため。
    • コンパイルされたオブジェクトファイルが依存先の情報も記録しているため。

インポートパス

  • import 宣言にあるインポートパスによってパッケージを一意に特定できる。
  • 言語仕様上、インポートパスの決定方法を定義しておらず、各ツールに任せている。
  • この章ではgoツールを前提にする。
  • 標準ライブラリ以外のパッケージは名前衝突を避けるために、パッケージ名をインターネットドメイン名から始めるべきである。

パッケージ宣言

  • package 宣言はすべてのGoファイルの先頭に必須である。
  • 慣習的にパッケージ名はインポートパスの最後の部分になる。
  • ただし、以下は例外である。
    • mainパッケージ。
    • ファイル名が_test.goで終わる場合、パッケージ名も_testで終わることができる。
      • つまりディレクトリに2つのパッケージを置くことができる。
    • インポートパスにバージョン番号がある場合、パッケージ名はそのバージョン番号を取る。

インポート宣言

  • Goファイルではpackage宣言の直後に0個以上のimport宣言を書くことができる。
  • 同じ名前を持つパッケージをインポートする場合、改名インポートが使用される。
    • 改名インポートはそのファイルにのみ影響を与える。同じパッケージの別ファイルには影響を与えない。
import (  
        "crypto/rand"  
        mrand "math/rand"  
)  
  • 改名インポートは衝突がない場合でも役立つ。
    • 自動生成されたコードのパッケージ名が扱いづらいとき。
    • パッケージと同じ名前のローカル変数名を多く持ちたいとき。

ブランクインポート

  • パッケージをインポートする必要はあるが、そのパッケージを呼び出さない場合、ブランクインポートをする必要がある。
import _ "image/png"  
  • これはパッケージで定義されている変数の初期化やinit関数を実行するために使用される。
  • 例えば image.Decodeはデコードできる形式を登録する必要がある。これはimage/jpegimage/pngのinit関数で行っている。
  • 同じように、database/sqlで使用できるドライバは各ライブラリのinit関数で登録される。

パッケージと命名

  • パッケージ名は
    • 簡潔でかつ意味がとおるようにする。
    • 説明的でかつ曖昧にならないようにする。
    • 単数形にする。
    • 他の意味を持つ名前を避ける。
      • 例: "temp": temperature, temporary
    • ローカル変数で使われる名前を避ける。
  • パッケージのメンバー名は
    • パッケージ名合わせて意味が通るようにする。
    • 単一の型を提供する単一型パッケージrand.Randなど重複しないように注意する

Goツール

  • goツールは
    • パッケージマネージャである。
    • ビルドシステムである。
    • テストドライバである。

ワークスペースの構成

パッケージのダウンロード

  • go get を使うことでインターネット上のパッケージもインストールできる。
  • go getGitHubなどの有名なホスティングサイトをサポートしており、Gitのようなバージョン管理システムをサポートしている。
    • つまり、単なるファイルコピーではなくクライアントである。
  • インポートパスとホスティングされているファイルのドメイン名は必ずしも一致しない。
    • インポートパスにHTTPアクセスをするとHTMLが返り、その中の <meta name="go-import">ホスティングの情報が書かれている。
    • 例: <meta name="go-import" content="golang.org/x/net git https://go.googlesource.com/net">

パッケージのビルド

  • go build
    • 引数に渡されたパッケージをコンパイルできる。
      • パッケージがライブラリ(main以外)の場合はコンパイル結果は破棄される。
      • パッケージがmainの場合はリンカが呼ばれ、実行ファイルが作成される。
      • パッケージはインポートパスや . で始まる相対パスで指定できる。
      • カレントディレクトリに実行ファイルが生成される。
    • 引数でファイル名を指定することもできる。
      • go build をしてそのファイルを実行するためのコマンド go run がある。
      • .go で終わっていない引数はプログラムへの引数として解釈される。
  • go install
  • go buildgo install は1度実行されると、それ以降変更されていない場合はコンパイルを実行しない。
  • net_linux.go などOSやアーキテクチャ名の入っているファイルは、それをターゲットにしている場合のみコンパイルされる。
  • 以下のようなビルドタグをパッケージ宣言の前に書くことでビルドを制御できる
// +build linux darwin  
// +build ignore  

パッケージのドキュメント化

  • パッケージのAPIにはドキュメンテーションコメントを書く慣習がある。
  • コメントは宣言名から始まる要約文になる。
  • コードと同様にドキュメンテーションも簡潔性と単純さが好まれる。
  • パッケージのドキュメンテーションコメントはdoc.goという名前のファイルに書かれることが多い。
  • go docを使うとドキュメントを参照できる。
    • 完全なインポートパスや大文字小文字を必要としない。(最後の例)
go doc time  
go doc time.Slice  
go doc time.Duration.Seconds  
go doc json.decode  
  • godoc コマンドを使うとドキュメントを表示するWebサーバを立ち上げることができる。
godoc -http :8000  

インターナルパッケージ

  • インポートパスにinternalが含まれている場合、go buildはそのパッケージを特別に扱う
  • 例えば、net/http/internal/chunkednet/http/httputilnet/httpからは参照できるがnet/urlからは参照できない。

パッケージの問い合わせ

  • go list を使うと利用可能なパッケージを調べることができる。
  • ワイルドカード ... を使用できる。
  • -jsonJSON形式で出力できる。
  • -f を使うと template/text のテンプレートで出力形式を定義できる。
go list -f '{{join .Deps " "}}' strconv