ludwig125のブログ

頑張りすぎずに頑張る父

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
}