go言語で呼び出す関数を動的に変更する
package main import ( "fmt" ) func main() { funcList := []func(){function1, function2, function3} for i:=0; i < 3; i++{ funcList[i]() } } func function1() { fmt.Println("print function1") } func function2() { fmt.Println("print function2") } func function3() { fmt.Println("print function3") }
実行結果
print function1 print function2 print function3
実行例 https://play.golang.org/p/MQnTJWIu7P1
参考にしたページ C# - 関数名call1, call2, call3...の連続実行をまとめる方法はありますか?|teratail
応用
上のを応用して自前のretry関数の挙動を確かめたもの
スプレッドシートへの書き込みを3回失敗するまでretryする関数を作りたかった
https://play.golang.org/p/HV0uqiVphap
以下は、3回失敗するまでretryをする関数とその実行例
- test1は、3回とも失敗するのでinsertedは0
- test1は、3回目で成功するのでinsertedは10
package main import ( "errors" "fmt" "time" ) type Resp struct { status int } func main() { target, inserted := retry([]func()(Resp, error){returnStatus1, returnStatus2, returnStatus3}) fmt.Printf("test1. target %d, inserted: %d", target, inserted) fmt.Printf("\n----------------------\n") target, inserted = retry([]func()(Resp, error){returnStatus1, returnStatus2, returnStatus4}) fmt.Printf("test2. target %d, inserted: %d", target, inserted) } func retry(returnStatusList []func()(Resp, error)) (int, int) { target_num := 10 fmt.Printf("insert target num: %v\n", target_num) var MaxRetries = 3 for attempt := 0; attempt < MaxRetries; attempt++ { resp, err := returnStatusList[attempt]() if err != nil { fmt.Printf("Unable to write value. %v. attempt: %d\n", err, attempt+1) time.Sleep(3 * time.Second) // 3秒待つ continue } status := resp.status if status != 200 { fmt.Printf("HTTPstatus error. %v. attempt: %d\n", status, attempt+1) time.Sleep(3 * time.Second) // 3秒待つ continue } // 書き込み対象の件数と成功した件数 fmt.Printf("succeded to write value.\n") return target_num, target_num } fmt.Printf("Failed to write data to sheet. reached to MaxRetries: %d\n", MaxRetries ) // 書き込み対象の件数と成功した件数 return target_num, 0 } func returnStatus1() (Resp, error) { resp := Resp{} resp.status = 200 err := errors.New("error! happend") return resp, err } func returnStatus2() (Resp, error) { resp := Resp{} resp.status = 404 return resp, nil } func returnStatus3() (Resp, error) { resp := Resp{} resp.status = 201 return resp, nil } func returnStatus4() (Resp, error) { resp := Resp{} resp.status = 200 return resp, nil }
結果
insert target num: 10 Unable to write value. error! happend. attempt: 1 HTTPstatus error. 404. attempt: 2 HTTPstatus error. 201. attempt: 3 Failed to write data to sheet. reached to MaxRetries: 3 test1. target 10, inserted: 0 ---------------------- insert target num: 10 Unable to write value. error! happend. attempt: 1 HTTPstatus error. 404. attempt: 2 succeded to write value. test2. target 10, inserted: 10
少し書き換え
上のはretryの中で回数を指定しているのが気に食わなかったのでちょっと修正。 getReturnStatusというラップ関数を用意
https://play.golang.org/p/hQK-TunSAWE
package main import ( "errors" "fmt" "time" ) type Resp struct { status int } func main() { target, inserted := retry() fmt.Printf("test1. target %d, inserted: %d", target, inserted) } func retry() (int, int) { target_num := 10 fmt.Printf("insert target num: %v\n", target_num) var MaxRetries = 3 for attempt := 0; attempt < MaxRetries; attempt++ { resp, err := getReturnStatus() if err != nil { fmt.Printf("Unable to write value. %v. attempt: %d\n", err, attempt+1) time.Sleep(3 * time.Second) // 3秒待つ continue } status := resp.status if status != 200 { fmt.Printf("HTTPstatus error. %v. attempt: %d\n", status, attempt+1) time.Sleep(3 * time.Second) // 3秒待つ continue } // 書き込み対象の件数と成功した件数 fmt.Printf("succeded to write value.\n") return target_num, target_num } fmt.Printf("Failed to write data to sheet. reached to MaxRetries: %d\n", MaxRetries ) // 書き込み対象の件数と成功した件数 return target_num, 0 } var count = 0 func getReturnStatus() (Resp, error) { funcList := []func()(Resp, error){returnStatus1, returnStatus2, returnStatus3} count++ return funcList[count-1]() } func returnStatus1() (Resp, error) { resp := Resp{} resp.status = 200 err := errors.New("error! happend") return resp, err } func returnStatus2() (Resp, error) { resp := Resp{} resp.status = 404 return resp, nil } func returnStatus3() (Resp, error) { resp := Resp{} resp.status = 201 return resp, nil } func returnStatus4() (Resp, error) { resp := Resp{} resp.status = 200 return resp, nil }