コマンドラインツール

プログラム引数

flagパッケージ

入出力の抽象化

io.Readerとio.Writer 読み書きに関するものを抽象化 書き込み先や読み込みもとを意識せずに使える ioする箇所とエンコーディングの箇所を切り離せる Unix のパイプのように、io.Readerとio.Writeをくっつけられうので便利

  • fmt.Fprintf(os.Stderr, “エラー”)
    • コマンドツールを作るときのコツは、コマンドが汚れないようにすること。エラーにしておくとパイプ先に渡されない。

プログラムの終了

Os.Exit 0が成功, 0以外を指定してやる

log.fatal だと、終了コードは1に限定される。 基本的にはlog.fatal は使うことはないと認識しておく。 特にmainパッケージ以外では使わない。

1行ずつ読み込む

Buffo.Scannerを使用する

ファイルを扱う

osパッケージを使う os.Createで書き込みを行なった場合は、Closeの前にエラー処理をする。

defer

同ブロック内でdeferを複数行なった場合、最後のdeferから順に実行される。スタック形式。

ファイルパスを扱う

Path/filepathパッケージを使う

OSに寄らないファイルパスの処理が行える

ディレクトリをウォークする

Filepath.Walkを使う

抽象化

インタフェース

Goではインターフェースでしか抽象化することができない implementsを使用しない モックを使う時などは、interface を先に自分で規定して使うと良い

type Stringer interface {
	String() string
}
// インタフェースを実装していることになる
var s Stringer = Hex(100)
fmt.Println(s.String())

empty interface

interfaceのメソッドの集合が空集合

var v interface{}
v = 100
v = "hoge"

スライスとインタフェース

実装していてもスライスは互換がない,

インタフェースの実装チェック

型スイッチ

var i interface{}
i = 100
switch v := i.(type) {
	case int:
		fmt.Println(v*2)
	case string:
		fmt.Println(v+"hoge")
	default:
		fmt.Println("default")
}

インタフェースの設計

  • 共通点を抜き出して実装しない
    • だいたい失敗する
  • 抽象化を本当にしなければいけない部分のみ抽象化する

埋め込みとインターフェース

埋め込み … 名前のないフィールドとして、構造体に構造体を組み込む 楽にアクセスできる。

type Hoge struct {N int}
type Fuga struct {Hoge}

f := Fuga{Hoge{N:100}}
// Hoge型のフィールドにアクセスできる
fmt.Println(f.N)
// 型名を指定してアクセスできる
fmt.Println(f.Hoge.N)

インタフェースの合成

インタフェースにインタフェースを埋め込む 埋め込まれたインタフェースの実装を変えた時も、埋め込み元の変更の必要がない

エラー処理

エラー

errorインタフェース

Ras cox のエラーについての話が良い

エラーに文脈を持たせる

何をしようとした時にエラーが起きたか知りたい errors.Wrapを使うとエラーをラップできる errors.Causeを使うと元のエラーが取得できる

パニックとリカバー

パニック 基本的にパニックは使わない。改善不良、回復不可である時。panicは書くな。

リカバー パニックを回復する。パニックの際は処理が中断するが、deferは実行される。なのでリカバーはdeferで実行される。

Exceptionとは全く異なる。同じように使わない。

テストとテスタビリティ

testingパッケージ

関数の名前の頭にTestがある、引数にtestingをとっているものを実行

テストのパッケージは、テスト対象と分けておく

Parallel テスト関数を複数同時に実行できる。早くできる

ベンチマーク 速さの証明。速さを売りにしているライブラリには書かれていることが多い。

testing/quick 境界値を見て、ランダムにブラックボックスを実行してくれる。

テスティングフレームワーク testify すらも、あまり使わない方が良い アサーションのライブラリをプロジェクト内で作ることは良い。 テストのための学習コストが必要になるのは、よくない。 go-cmp を使うと、diffを撮ったり、0.0001などの許容をしてくれたりする。

Exampleテスト

ExampleをREAD.me に書いておくと、修正を忘れがち。

サブテストとテーブル駆動テスト

テストケースとテストロジックの分離

シャドーイングに注意!

テストヘルパー

テストヘルパーは、準備のためのヘルパーであり、本ロジックのテストには使用するものではない。 なので、基本的にはエラーを返さない。t.Fatalで落とす。 落ちたときの情報を整理してくれる。

てスタビリティ

モックを使う理由 テストの再現性を担保するため。

モックを使う場合は基本的にインタフェースを使用する。

環境変数を構造体にマッピングしてくれるパッケージがある。Third partyで viperなど。spf13さん

testdata _で始まるディレクトリ、testdataという名前のディレクトリはパッケージに含まれない。

export_test.go

依存しているものを羅列するために書く

宿題

  • タイピングゲーム
    • 細かいルールは適当に決めて、宣言、
    • 制限時間内
    • キーボードが待ち受けている時間の制御にgoroutine
  • 分割ダウンロード
    • goroutineで複数投げて、取得後に合体させる。