Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Go言語でTDDする勉強会 第4回(2020/01/08) 予習メモ

Go言語でTDDする勉強会 第4回(2020/01/08) 予習メモ

connpass

Go言語でTDDする勉強会 (初心者大歓迎!)

今回の発表者


第2回発表メモ, 第3回発表メモ のように 細かく箇条書きにするのも面倒になってきたので、 各章の概要だけ、、、、

 

8. Maps

8. Maps

要件

map を基底とした Dictionary 型 を定義

type Dictionary map[string]string

自分で定義した custom type の Dictionary 型 に対して、 CRUD (Create, Read, Update, Delete) API を以下の順で実装していく

  • Search メソッド (Read)
    • 指定した key が map に存在しない場合ErrNotFound を返す
      • map の振る舞いをそのまま利用すると ゼロ値が返る ※後述 (v := map["new_key"])
  • Add メソッド (Create)
    • 既に同じ key が map に登録されていた場合ErrWordExists を返す
      • map の振る舞いをそのまま利用すると Update になってしまう (map["exists_key"] = "val")
  • Update メソッド
    • 指定した key が map に存在しない場合ErrWordDoesNotExist を返す
      • map の振る舞いをそのまま利用すると Create になってしまう (map["new_key"] = "val")
  • Delete メソッド
    • 組み込みの delete 関数 をそのまま利用.
      • 指定した key で map に存在しない場合は 無視される
      • 戻り値無し

map の特徴

key type

  • comparable type のみ
    • slice, map, function は not comparable なので key に指定できない

Reference Types

  • map is a reference type (map は 参照型) -> nil になる可能性有り

空のマップ変数を初期化しては

var m map[string]string

map の作成方法

var dictionary = map[string]string{}

// OR

var dictionary = make(map[string]string)
  • 補足: A Tour of Go: Maps 参照
    • > マップのゼロ値は nil です
    • > nil マップはキーを持っておらず、またキーを追加することもできません
    • > make 関数は指定された型の、初期化され使用できるようにしたマップを返します
  • 補足: 50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang DevsUsing "nil" Slices and Maps 参照
    • > It's OK to add items to a "nil" slice, but doing the same with a map will produce a runtime panic. ("nil" slice にアイテムを追加してもかまいませんが、 map で同じ操作を行うと runtime panic が発生します)

map の戻り値 2個

	definition, ok := d[word]
	if !ok {
		return "", ErrNotFound
	}
  • key が存在しない場合
    • 1個目の戻り値 = ゼロ値(string の場合は "")
    • 2個目の戻り値 = false

error を抽出

  • error を variable として定義
var ErrNotFound = errors.New("could not find the word you were looking for")

↓ リファクタリング

  • error を const に変更
    • string を 基底 とした Custom Type を定義
    • Error() string メソッド を実装 -> error interface を満たす
    • string なので const 化できる
const (
	ErrNotFound = DictionaryErr("could not find the word you were looking for")
	ErrWordExists = DictionaryErr("cannot add word because it already exists")
	ErrWordDoesNotExist = DictionaryErr("cannot update word because it does not exist")
)

type DictionaryErr string

func (e DictionaryErr) Error() string {
	return string(e)
}
  • 補足: A Tour of Go: Constants 参照
    • > 定数は、文字(character)、文字列(string)、boolean、数値(numeric)のみで使えます

最終結果

v7

 


9. Dependency Injection

9. Dependency Injection

要件

  • Greet 関数 の test を行う
    • fmt.Fprintf を利用して writer に string を書き込む 関数

Greet 関数 の実装

v2 の di.go

func Greet(writer io.Writer, name string) {
	fmt.Fprintf(writer, "Hello, %s", name)
}
  • 第1引数 の io.Writer に対して DI する
    • test では -> *bytes.Buffer
    • main 関数 からは -> os.Stdout
    • HTTP server では -> http.ResponseWriter

前提知識

io.Writer

io.Writer

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

*bytes.Buffer, os.Stdout, http.ResponseWriter

fmt.Printf, fmt.Fprintf

  • fmt.Printf は 中で fmt.Fprintf を呼び出し
    • fmt.Fprintf第1引数 に os.Stdout (実体は *os.File) を渡している
func Printf(format string, a ...interface{}) (n int, err error) {
	return Fprintf(os.Stdout, format, a...)
}
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
	// 中略
}

 

補足: http.HandlerFunc

http.HandlerFunc の定義

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}
  • HandlerFunc は 関数 func(ResponseWriter, *Request) 」 型 を 基底 とする 型
    • -> 関数 func(ResponseWriter, *Request)HandlerFunc 型 に 変換可能
  • HandlerFuncServeHTTP メソッド を持つ
    • ServeHTTP メソッド は 関数自身(=f) を呼び出す
  • 後の章 12. Select, 15. Context でまた出ます

補足: http.ListenAndServe 関数

http.ListenAndServe の定義

func ListenAndServe(addr string, handler Handler) error {
	// 中略
}
  • 第2引数Handler interface

補足: http.Handler interface

http.Handler の定義

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}
  • HandlerFuncServeHTTP メソッド を持つ
    • -> Handler interface を満たす
    • -> Handler 型 の変数に 代入可能
      • -> ListenAndServe第2引数 に 渡せる
func MyGreeterHandler(w http.ResponseWriter, r *http.Request) {
	Greet(w, "world")
}

func main() {
	err := http.ListenAndServe(":5000", http.HandlerFunc(MyGreeterHandler))

	if err != nil {
		fmt.Println(err)
	}
}

最終結果

v2

 

※今回はここまで

次回 -> 第5回(2020/01/22) 実施です (第5回(2020/01/22) 発表メモ)

 


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.