go – Pass variable into callback function-ThrowExceptions

Exception or error:

Is the the way to pass the selector variable into the callback function?

for _, selector := range listSelector {
    c.OnHTML(selector, func(e *colly.HTMLElement) {
        fmt.Println(selector) // Similar outputs

Expected result are the different selector for the output.

How to solve:

Depending on when the callback is executed you may need to create a copy of the iteration variable inside the block and use that in the closure.

for _, selector := range listSelector {
    sel := selector // create a copy
    c.OnHTML(sel, func(e *colly.HTMLElement) {
        fmt.Println(sel) // Similar outputs

If the callback is executed and it exits before the next iteration in the loop you do not need to do this, however if the callback is executed sometime later you need to pass a copy of the iteration variable to the closure. This is because the iteration variable is reused to hold the iterated-over values, which means that the variable’s value from the current iteration will be overwritten with the value from the next iteration.

From the spec:

The iteration variables may be declared by the “range” clause using a
form of short variable declaration (:=). In this case their types are
set to the types of the respective iteration values and their scope is
the block of the “for” statement; they are re-used in each iteration.
If the iteration variables are declared outside the “for” statement,
after execution their values will be those of the last iteration.

If you’re interested, this is better explained in the Effective Go documentation on Channels.

Leave a Reply

Your email address will not be published. Required fields are marked *