post Image
標準パッケージから見るパッケージ構成のパターンの解説

こんにちは!これはGo3 Advent Calendar 2018、2日目の記事です。
1日目は、higasgtさんのredisを扱うコードをユニットテストするでした。

TL;DR

  • Goのパッケージ構成は、標準パッケージでも複数パターンの構成が存在している
  • 習う際は、いくつかのパッケージ構造を比較してどのように実装するかを決めるのが良い
  • io と database/sql は有名な標準パッケージだがパッケージ構成のアプローチは異なる

ioパッケージの構成について

ioパッケージは io.Reader io.Writer をはじめとして有名なパッケージです。
Goを触っている人は ioutil.ReadAll() にお世話になった人も多いのではないでしょうか。

io
├── example_test.go
├── io.go
├── io_test.go
├── ioutil
│   ├── example_test.go
│   ├── ioutil.go
│   ├── ioutil_test.go
│   ├── tempfile.go
│   ├── tempfile_test.go
│   └── testdata
│       └── hello
├── multi.go
├── multi_test.go
├── pipe.go
└── pipe_test.go

ioパッケージを構成するディレクトリ構造は上記のようになっています。
1つづつ解説していきます。

io.go

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}

io.go は Reader Writer Closer をはじめとする抽象を実装しています。
パッケージのコメントに書いてある通りです。

Package io provides basic interfaces to I/O primitives.
Its primary job is to wrap existing implementations of such primitives, such as those in package os, into shared public interfaces that abstract the functionality, plus some other related primitives.

ioutil/ioutil.go

ioutilパッケージについては、下記のコメントのようにいくつかのutilityを実装しています。

Package ioutil implements some I/O utility functions.

具体的な実装として呼び出す際は下記のように ioutil の具象実装を利用します

r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")

b, err := ioutil.ReadAll(r)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%s", b)

なので、パッケージ構成としては下記のように、ioが抽象 / io/ioutilが具象となっています。


io // 抽象
├── example_test.go
├── io.go
├── io_test.go
├── ioutil // 具象
│   ├── example_test.go
│   ├── ioutil.go
│   ├── ioutil_test.go
│   ├── tempfile.go
│   ├── tempfile_test.go
│   └── testdata
│       └── hello
├── multi.go
├── multi_test.go
├── pipe.go
└── pipe_test.go

database/sql

database/sqlパッケージについてもioの時と同様に追いかけていきましょう。

sql/
├── convert.go
├── convert_test.go
├── ctxutil.go
├── doc.txt
├── driver
│   ├── driver.go
│   ├── types.go
│   └── types_test.go
├── example_test.go
├── fakedb_test.go
├── sql.go
└── sql_test.go

パッケージ構成は上記のようになっています。

sql.go

func Open(driverName, dataSourceName string) (*DB, error) {
    driversMu.RLock()
    driveri, ok := drivers[driverName]
    driversMu.RUnlock()
    if !ok {
        return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
    }

    if driverCtx, ok := driveri.(driver.DriverContext); ok {
        connector, err := driverCtx.OpenConnector(dataSourceName)
        if err != nil {
            return nil, err
        }
        return OpenDB(connector), nil
    }

    return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}

sql.goは上記のように、 driveri, ok := drivers[driverName] という行で Driver を取り出して処理します。
Driver は ioの時とは逆に、driver ディレクトリの中に実装されており、 Driver インターフェースなど抽象実装がされています

type Driver interface {
    // Open returns a new connection to the database.
    // The name is a string in a driver-specific format.
    //
    // Open may return a cached connection (one previously
    // closed), but doing so is unnecessary; the sql package
    // maintains a pool of idle connections for efficient re-use.
    //
    // The returned connection is only used by one goroutine at a
    // time.
    Open(name string) (Conn, error)
}

go-sql-driver/driver.go

このDriverを使用しているのが go-sql-driverパッケージです。
以下のように init() 関数でDriverを登録し、その後の処理で利用しています。

func init() {
    sql.Register("mysql", &MySQLDriver{})
}

パッケージの構成がioとは逆で、以下のようになります。

sql/ // 具象
├── convert.go
├── convert_test.go
├── ctxutil.go
├── doc.txt
├── driver // 抽象
│   ├── driver.go
│   ├── types.go
│   └── types_test.go
├── example_test.go
├── fakedb_test.go
├── sql.go
└── sql_test.go

まとめ

  • パッケージの構成は標準パッケージでも異なる
  • 自分の実装の参考にする際は、複数のパッケージ構成を見比べた上でメリットがある方をえらぶとよい

おわりに

今日は標準パッケージの読み方を紹介しました。
明日は m_green14 さんです!


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。