|
package main |
|
|
|
import "fmt" |
|
|
|
func main() { |
|
data := Data{[]string{"main"}} |
|
a := wrap(data, "A", func(data Data) { |
|
fmt.Printf(" in func A: %#v\n", data) |
|
}) |
|
b := wrap(data, "B", func(data Data) { |
|
fmt.Printf(" in func B: %#v\n", data) |
|
}) |
|
|
|
a() |
|
a() |
|
a() |
|
b() |
|
b() |
|
|
|
// Output: |
|
// wrapping func A: main.Data{Value:[]string{"main"}} |
|
// wrapping func B: main.Data{Value:[]string{"main"}} |
|
// calling func A: main.Data{Value:[]string{"main", "A"}} |
|
// in func A: main.Data{Value:[]string{"main", "A"}} |
|
// calling func A: main.Data{Value:[]string{"main", "A", "A"}} |
|
// in func A: main.Data{Value:[]string{"main", "A", "A"}} |
|
// calling func A: main.Data{Value:[]string{"main", "A", "A", "A"}} |
|
// in func A: main.Data{Value:[]string{"main", "A", "A", "A"}} |
|
// calling func B: main.Data{Value:[]string{"main", "B"}} |
|
// in func B: main.Data{Value:[]string{"main", "B"}} |
|
// calling func B: main.Data{Value:[]string{"main", "B", "B"}} |
|
// in func B: main.Data{Value:[]string{"main", "B", "B"}} |
|
} |
|
|
|
func wrap(data Data, name string, f func(Data)) func() { |
|
fmt.Printf("wrapping func %s: %#v\n", name, data) |
|
return func() { |
|
// This modifies `data` in the outer scope, even though WithValue |
|
// returns a new "instance" of Data, so subsequent calls to the wrapped |
|
// function will accumulate additional values. |
|
// |
|
// This caught me off guard, though it probably shouldn't have. |
|
// |
|
// The fix is to use := instead of = to declare a new variable with the |
|
// same name that would shadow `data` in the outer scope (or just use a |
|
// different name altogether). |
|
data = data.WithValue(name) |
|
fmt.Printf(" calling func %s: %#v\n", name, data) |
|
f(data) |
|
} |
|
} |
|
|
|
type Data struct { |
|
Value []string |
|
} |
|
|
|
func (d Data) WithValue(val string) Data { |
|
return Data{append(d.Value, val)} |
|
} |