プログラミング言語 Go 第10章 パッケージとGoツール

プログラミング言語 Go 第10章 パッケージとGoツール

A.A.A.Donovan, B.W.Kernighanらの『プログラミング言語 Go』第10章 パッケージとGoツールの輪講資料です。

B168d7837ed7b41e4f0c1d952823628f?s=128

WATANABE Takuma

September 14, 2016
Tweet

Transcript

  1. プログラミングGO 第10章 『パッケージとGOツール』 WATANABE Takuma (takumaw@sfo.kuramae.ne.jp) 1 2016/09/14

  2. Preface (1/2) ¨  控えめなサイズのプログラムでも、 およそ10000のfunctionを含むと言われている。 ¤  そのうち大多数は、パッケージから与えられた (再利用された)ものである。 ¨  Goは100を越すパッケージを提供する。

    ¤  コミュニティによるパッケージはhttp://godoc.orgから 利用できる。 2
  3. Preface (2/2) 3 ¨  本章では: ¤  パッケージを利用・作成する方法を解説。 ¤  パッケージ管理ツールであるgoコマンドについて解説。 n 

    根底にあるコンセプト n  download, build, run以外の機能 n  ワークスペースにあるパッケージのメタデータ検索 n  ドキュメント表示 n  etc…
  4. Introduction (1/2) 4 ¨  パッケージシステムの目的とは ¤  類似機能を単位ごとにまとめ、巨大プログラムの設計・維 持を実現すること。 n  ここでいう単位:

    容易に理解でき、独立してアップデート出来る 単位。 ¨  モジュール性をもたせると、再利用が可能となる。 ¨  パッケージは独立した名前空間を持つ。 ¤  このおかげで、型や関数について、競合を防げる。 ¨  パッケージはカプセル化を提供する。 ¤  つまり: パッケージ外から見える名前を制御する。 ¤  APIの変更なしに、パッケージの実装を変えることを可能 にする。
  5. Introduction (2/2) 5 ¨  Goでは、パッケージのファイルを変更した場合、 パッケージごと再コンパイルが必要。 ¤  そして、それに依存する外部パッケージも… ¨  といっても、Goのコンパイルは高速である。

    ¤  他のコンパイル言語と比較しても。 ¤  スクラッチビルドであっても! ¨  コンパイルが速い3つの理由: 1.  インポート文は必ずソース先頭にある。 2.  循環インポートなし。 n  だから、独立して(恐らく並列に)コンパイル可能。 3.  コンパイル済みのオブジェクトに、依存関係情報あり。
  6. Table of Contents 6 ¨  10.2. Import Paths ¨  10.3.

    パッケージ宣言 ¨  10.4. インポート宣言 ¨  10.5. 空の(blank)インポート宣言 ¨  10.6. パッケージの命名 ¨  10.7. The Go Tool ¤  ワークスペースの構成 ¤  パッケージのダウンロード ¤  パッケージのビルド ¤  パッケージのドキュメント ¤  内部パッケージ ¤  パッケージの検索
  7. 10.2. Import Paths 7 ¨  パッケージはimport pathによって一意に識別される。 ¨  言語仕様上は、import pathの生成規則に制約はない。

    ¤  本書ではGo ツールの動作にもとづいて解説している。 ¤  異なるルールに従う異なるツールも存在する。(Googleの 内部コンパイルシステムなど) ¨  import pathはグローバルに一意である必要がある。 ¤  標準ライブラリ以外のパッケージは、 所有者/ホスト者のインターネットドメイン名で始めること。 ¤  一意性の確保のほか、探しやすさの向上にもなる。
  8. 10.3.パッケージ宣言 8 ¨  Goで書かれたソースコードは、 必ず先頭にパッケージ宣言がなくてはならない。 ¨  パッケージ内の全ファイルに宣言が必要。 ¨  例: math/rand中のファイルではpackage

    randと宣言されているため、 いかなるメンバーもrand/XXXでアクセス可能。 package main import ( "fmt" "math/rand" ) func main() { fmt.Println(rand.Int()) }
  9. 10.3.パッケージ宣言 9 ¨  パッケージ宣言 ¤  import pathの最後のセグメントがパッケージ名となる。 n  last segment

    conversionと呼ぶ。 n  (※math/randならrand) ¤  ゆえに、例えばmath/randとcrypto/randは 同じrandというパッケージ名を持ちうる。 ¤  回避方法は後述。
  10. 10.3. パッケージ宣言 10 ¨  Last segment conversionの例外 (3つ) 1.  Goの実行ファイルを与えるパッケージは常にmain

    2.  ファイル名が_testで終わる場合、 “_test”つきのパッケージ名を定義する。 n  通常のパッケージと、外部テストパッケージ (external test package)を定義する。 n  この仕組が循環参照を防ぐ。(11.2.4で詳説) 3.  依存関係管理ツールのなかには、 import pathの末尾にバージョンを付与するものもある。 n  パッケージ名からはバージョンが除外される。 n  例: gopkg.in/yaml.v2 の場合、yamlとなる。
  11. 10.4.インポート宣言 11 ¨  Goのソースは、package宣言、import宣言(あれば)、 import以外の文の順で成る。 ¨  複数のimport文を空行で区切ることで、 グループ化できる。 ¤  ドメインごとにグループ化し、

    グループ内では、alphabeticallyにsortするのが通常。 ¤  gofmtとgoimportsでそれを実現できる。 ¨  循環参照は、go build でチェックできる。 import "fmt” import "os” import ( "fmt" "os" ) import ( "fmt” "html/template” "os” "golang.org/x/net/html” "golang.org/x/net/ipv4” )
  12. 10.4. インポート宣言 12 ¨  パッケージを別名でインポートすることができる。 ¤  renaming importと呼ぶ。 ¤  別名をalternative

    nameと呼ぶ。 ¤  同一ファイル内でのみ有効。 ¤  同一名のパッケージをインポートする場合は必須。 ¤  自動生成コードなど、イマイチな名前の回避にも有効。 ¤  リネーミングには一貫性を持たせること。 import ( "crypto/rand“ mrand "math/rand“ )
  13. 10.5.空の(blank)インポート宣言 13 ¨  コード中で参照されないパッケージのimport宣言は エラーとなる。 ¨  しかし、副作用目当てにimportが必要となることはしばし ある。 ¤  Package-level変数の初期化コードや、パッケージのinit関数

    呼び出しの処理を期待する場合など。 ¨  Alternative nameに”_”を用いることで回避する。 ¤  Blank importと呼ぶ。 ¤  “_”はThe blank identifierと呼ばれる。
  14. 10.5. 空の(blank)インポート宣言 14 ¨  例: コア機能と各ドライバの分離などに用いられる。 ¤  それらはinitで初期化処理(登録処理)をする。 package main

    import ( "fmt” "image” "image/jpeg” _ "image/png" // register PNG decoder "io” "os” ) import ( "database/mysql“ _ "github.com/lib/pq“ // enable support for Postgres _ "github.com/go-sql-driver/mysql“ // enable support for MySQL )
  15. 10.6.パッケージの命名 15 ¨  Goにおけるパッケージ名・メンバ名の 慣例的な命名規則を示す。 ¨  パッケージの命名規則: ¤  短くしろ、しかし暗号符丁的にはするな。 n 

    bufio, bytes, flag, fmt, http, io, json, os, sort, sync, and time など。 ¤  記述的で、明確にせよ。 n  例えば、ユーティリティパッケージをutilと命名するのは好 ましくない。 n  ローカル変数名によく用いられる名前も好ましくない。 (alternative name)
  16. 10.6.パッケージの命名 16 ¨  パッケージの命名規則: ¤  一般的に単数形を用いよ。 n  標準パッケージのBytes, errors, stringに関しては、既存型

    および予約語との重複回避のため、複数形を用いている。 ¤  他の含意を持っている言葉を避けよ。 n  Temperatureの意味でtempを用いると、Temporaryの意味と 取られる。
  17. 10.6. パッケージの命名 17 ¨  メンバの命名規則: ¤  パッケージ名も役割記述を担っている。 メソッド名だけで記述しきるな。 例: bytes.Equal,

    http.Get, json.Marshal, http.Get ¤  single-type packageという種のパッケージでは、 1つの型、1つのメソッドがexportされる。 n  繰り返しになりがち(template.Templateなど)なので、 特に短さが求められる。 ¤  他方、net/httpのように、複雑な構造をもたなくとも 多くのnameをexportするものもある。
  18. 10.7. The Go Tool 18 ¨  Go toolとは: ¤  Goコードのビルド・テスト・整形・ダウンロード・インス

    トール・検索ができるコマンド。 ¤  複数機能を持つ単一コマンド。 ¤  パッケージマネージャである。 n  パッケージインベントリを検索し、依存関係を解決し、VCS からダウンロードができる。 ¤  ビルドシステムである。 n  依存関係を解決し、コンパイラ・アセンブラ・リンカーを呼び 出せる。 ¤  テストドライバでもある。
  19. 10.7. The Go Tool 19 ¨  たくさんのサブコマンドをもつ。 $ go ...

    build compile packages and dependencies clean remove object files doc show documentation for package or symbol env print Go environment information fmt run gofmt on package sources get download and install packages and dependencies install compile and install packages and dependencies list list packages run compile and run Go program test test packages version print Go version vet run go tool vet on packages Use "go help [command]" for more information about a command. ...
  20. 10.7. The Go Tool 20 ¨  ワークスペース構成 ¤  GOPATH環境変数で指定したフォルダがワークスペー スとなる。

    ¤  ワークスペースを切り替えるには、単にGOPATHを変 えれば良い。 ¤  GOPATHは、多くの人にとっては、 唯一の設定しなければならない設定項目。
  21. 10.7. The Go Tool 21 ¨  ワークスペース構成 ¤  例 GOPATH/

      src/     gopl.io/       .git/       ch1/         helloworld/           main.go         dup/            main.go         ...     golang.org/x/net/       .git/         html/           parse.go           node.go           ...   bin/     helloworld     dup   pkg/     darwin_amd64/     ...
  22. 10.7. The Go Tool 22 ¨  ワークスペース構成 ¤  src/ n 

    ソースが入る。 n  Import pathに従いサブディレクトリが生成される。 ¤  pkg/ n  コンパイル済みパッケージが入る。 ¤  bin/ n  実行ファイルが入る。
  23. 10.7. The Go Tool 23 ¨  ワークスペース構成 ¤  GOROOTを指定することで、標準パッケージの ルートディレクトリも変更できる。

    n  配下の構造はGOPATH配下と同様。 n  通常は指定する必要はない。 ¤  go env コマンドで、その他の環境変数を一覧できる。 $ go env GOPATH="/home/gopher/gobook" GOROOT="/usr/local/go" GOARCH="amd64" GOOS="darwin" ...
  24. 10.7. The Go Tool 24 ¨  パッケージのダウンロード ¤  go get

    コマンドでダウンロード/インストールができる。 ¤  Import pathにもとづき、ダウンロードする。 ¤  …記法を用いることで、サブツリーの一括更新も可。 ¤  Go get コマンドはGitHubやBitbucket、Launchpadと いった著名なホスティングサイトに対応している。 n  その他のサイトについては、プロトコル(git, mercurial等)を 指定しないといけない。
  25. 10.7. The Go Tool 25 ¨  パッケージのダウンロード ¤  Go getコマンドの生成するパッケージディレクトリは、

    リモートリポジトリのクライアントとなっている。 n  ゆえに、ふつうのvcsコマンドが使える。 $ cd $GOPATH/src/golang.org/x/net $ git remote –v origin https://go.googlesource.com/net (fetch) origin https://go.googlesource.com/net (push)
  26. 10.7. The Go Tool 26 ¨  パッケージのダウンロード ¤  ページ中にメタデータを挿入することで、 パッケージ名とホスティングサイトを分離できる。

    ¤  以下は、golang.org/x/netの例。 実際はhttps://go.googlesource.com/net にホストされている。 https://golang.org/x/net/html 中の記述: <meta name="go-import" content="golang.org/x/net git https://go.googlesource.com/net">
  27. 10.7. The Go Tool 27 ¨  パッケージのダウンロード ¤  -uフラグで、依存関係も全てアップデートできる。 ¤ 

    -uフラグがない場合、ダウンロード済みの依存関係は そのまま放置される。 ¤  デプロイ済みコードなど、一括アップデートに難のあ るコードでは、Vendor Directoryを用いること。 (Go helpを参照)
  28. 10.7. The Go Tool 28 ¨  パッケージのビルド ¤  Go buildコマンドでパッケージがビルドできる。

    ¤  指定されたパッケージがmainの場合、 実行ファイルをコンパイルする。 n  ファイル名は、import pathのlast segment。 ¤  指定されたパッケージが単なるライブラリの場合、 コンパイルエラーがないかのチェックだけを行う。
  29. 10.7. The Go Tool 29 ¨  パッケージのビルド ¤  1ディレクトリ1パッケージの制約上、 各実行ファイル(コマンド)もまた

    各自のディレクトリに配置される必要がある。 ¤  cmdディレクトリのサブディレクトリに置かれることも多 い。 n  例: golang.org/x/tools/cmd/godoc
  30. 10.7. The Go Tool 30 ¨  パッケージのビルド ¤  Go buildのパッケージ名は3通り。

    n  import paths n  相対パス(必ず.か..で始めること) n  無指定(=カレントディレクトリ)
  31. 10.7. The Go Tool 31 ¨  パッケージのビルド ¤  Go buildにはファイル名も指定できる。(複数可)

    ¤  パッケージ名がmainの場合、1番目に指定された ファイル名がコマンド名となる。 ¤  Go run ファイル名… 引数… でコンパイルと実行が 行える。 n  .goで終わらない引数以降が、コマンドへの引数とみなさ れる。
  32. 10.7. The Go Tool 32 ¨  パッケージのビルド ¤  Go buildは実行ファイル以外は全て捨てる。

    ¤  Go installでは、コンパイル結果を$GOROOT/pkgに 保存する。 ¤  Go build -iは、依存関係のみ保存する。
  33. 10.7. The Go Tool 33 ¨  パッケージのビルド ¤  Pkg配下には、$GOOSと$GOARCHに基づいたサブ ディレクトリが作られる。

    n  例: $GOROOT/pkg/darwin_amd64 ¤  $GOOSと$GOARCHを変えるだけで、クロスコンパイ ルができる。 $ go build gopl.io/ch10/cross $ ./cross darwin amd64 $ GOARCH=386 go build gopl.io/ch10/cross $ ./cross darwin 386
  34. 10.7. The Go Tool 34 ¨  パッケージのビルド ¤  特定ファイルを特定のプラットフォームでのみ コンパイルさせたい場合、以下の指定方法がある。

    n  ファイル名: n  (例) net_linux.go や asm_amd64.s など。 n  コメント(build tag): n  パッケージ宣言(とdoc commen)の前に、以下のコメントを記述。 n  LinuxとMac用: // +build linux darwin n  一切コンパイルさせない場合: // +build ignore
  35. 10.7. The Go Tool 35 ¨  パッケージのドキュメント ¤  パッケージおよび各公開メンバには、 目的と利用法を記したドキュメントを与えねばならな

    い。 ¤  ドキュメントは常に文章であること。 ¤  第1センテンスは要約であることがふつう。 ¤  各種識別子(引数など)は地の文(引用符やマークアッ プなし)。 // Fprintf formats according to a format specifier and writes to w. // It returns the number of bytes written and any write error encountered. func Fprintf(w io.Writer, format string, a ...interface{}) (int, error)
  36. 10.7. The Go Tool 36 ¨  パッケージのドキュメント ¤  パッケージ宣言直後のコメントは、 パッケージ全体に対するdoc

    commentとなる。 ¤  巨大なコメントは、それだけで1ファイルに切り出す価 値がある。 n  ふつう、doc.goと命名する。 ¤  複数ファイルに書けるが、1つだけでなければならな い。 ¤  コメントもメンテナンス対象である以上、広範すぎず、 簡潔にすること。
  37. 10.7. The Go Tool 37 ¨  パッケージのドキュメント ¤  良いドキュメント例が知りたい場合、標準パッケージ のものを参照すると良い。

    n  パッケージ例: $ go doc time n  メンバ例: $ go doc time.Since n  メソッド例: $ go doc time.Duration.Seconds ¤  部分指定もできる。 n  $ go doc json.decode // → (*json.Decoder).Decode を表示 ¤  Godoc コマンドでブラウザからも読める。 n  $ godoc –http :8000 // → http://localhost:8000/pkg n  https://godoc.org を参照してもよい。
  38. 10.7. The Go Tool 38 ¨  内部パッケージ ¤  Import pathに”internal”を含むパッケージは、

    内部パッケージとして扱われる。 ¤  Internalの親ディレクトリ以下のパッケージからのみ 読み込み可能。 ¤  例: n  net/http ✓ n  net/http/internal/chunked 読み込み対象 n  net/http/httputil ✓ n  net/url ✗
  39. 10.7. The Go Tool 39 ¨  内部パッケージ ¤  ユーティリティ関数を内部共有したい場合、 未成熟なコードを検証したい場合などに有効。

  40. 10.7. The Go Tool 40 ¨  パッケージの検索 ¤  go list

    コマンドで利用可能なパッケージを一覧可。 ¤  “…”ワイルドカードも利用可。 $ go list ... archive/tar archive/zip bufio bytes cmd/addr2line cmd/api ...many more... $ go list gopl.io/ch3/... gopl.io/ch3/basename1 gopl.io/ch3/basename2 gopl.io/ch3/comma gopl.io/ch3/mandelbrot gopl.io/ch3/netflag gopl.io/ch3/printints gopl.io/ch3/surface $ go list ...xml... encoding/xml gopl.io/ch7/xmlselect
  41. 10.7. The Go Tool 41 ¨  パッケージの検索 ¤  JSON形式などで、完全なメタデータを吐き出すことも できる。

    $ go list -json hash { "Dir": "/home/gopher/go/src/hash", "ImportPath": "hash", "Name": "hash", "Doc": "Package hash provides interfaces for hash functions.", "Target": "/home/gopher/go/pkg/darwin_amd64/ hash.a", "Goroot": true, "Standard": true, "Root": "/home/gopher/go", "GoFiles": [ "hash.go” ], …
  42. 10.7. The Go Tool 42 ¨  パッケージの検索 ¤  -fコマンドで、アウトプットをカスタマイズできる。 n 

    text/template のテンプレート言語に従う。 ¤  検索だけでなく、ビルド・テスト自働化などでも有効。 $ go list -f '{{.ImportPath}} -> {{join .Imports " "}}' compress/... compress/bzip2 -> bufio io sort compress/flate -> bufio fmt io math sort strconv compress/gzip -> bufio compress/flate errors fmt hash hash/crc32 io time compress/lzw -> bufio errors fmt io compress/zlib -> bufio compress/flate errors fmt hash hash/adler32 io $ go list -f '{{join .Deps " "}}' strconv errors math runtime unicode/utf8 unsafe