Skip to content

golang closure

foolmacky edited this page Sep 11, 2021 · 3 revisions

■Goの関数はclosureです

for _, val := range values {
    go func() {
        fmt.Println(val)
    }()
}
//このloopでは中の関数がgoroutineになっているので、さきにloopが終了してしまい、valの値は最後の値(ここでは9)になる
//goroutineにスイッチされ、実際に実行されるが、各goroutineはこの最後の値を使って処理を行うため、期待した動作にならない。

//なので、この場合はvalをfuncの引数に渡すようにする
for _, val := range values {
    go func(val2) {
        fmt.Println(val2)
    }(val)  //<-------これはfor loopからfuncの呼び出しの引数
}
//クロージャー的に変数を参照できてしまうが、それはgoroutine生成時に渡されたものではない、ということ
  • lambdaのクロージャ https://oohira.github.io/gobyexample-jp/closures.html
  • 当然ながらクロージャとしてはメソッドを定義することはできない。lambdaとしてclosureを定義して、structのフィールドに格納、実行することはできる
import (
    "bufio"
    "log"
    "os"
)

type Task interface {
    Exec (arg interface{}) (interface{}, error)
}

type InLoop struct {
    Fexec func(arg interface{}) (interface{}, error)
}

func NewInLoop() InLoop {
    return InLoop(
        Fexec: buildExec()}
}

func buildExec() func(interface{}) (interface{}, error) {
    var ctext []string
    log.Println(ctext)
    return func (arg interface{}) (interface{}, error) {
        ctext = append(ctext, arg.(string))
        return ctext, nil
    }
}

func (inloop InLoop) Exec(arg interface{}) (interface{}, error) {
    log.Println("In Exec")
    return inloop.Fexec(arg)
}

func main() {
    pfile, perr := os.Opne("looptext")
    if perr != nil {
        log.Println(perr)
    }
    defer pfile.Close()
    pscanner := bufio.NewScanner(pfile)
    var mtext interface{}
    inloop := NewInLoop()

    tasks := []Task(inloop)

    for repet := 0; repet < 500; repet++ {
        if !pscanner.Scan() {
            log.Println("Pscanner error.")
            break
        }
        if perr = pscanner.Err(); perr != nil {
            log.Println(perr)
            break
        }

        for _, task := range tasks {
            mtext, _ = task.Exec(pscanner.Text())
        }
    }
}

Clone this wiki locally