Receivers in handler functions such as filepath.WalkFunc

I ran into a little problem for which I only have an ugly solution. I can not imagine that I am the first, but I did not find any clues about SO.

In the following (intentionally simplified) example, I would like to have a receiver on the walk function, which is my filepath.WalkFunc .

 package main import ( "fmt" "os" "path/filepath" ) type myType bool func main() { var t myType = true // would have loved to do something as: // _ = filepath.Walk(".", t.walk) // that does not work, use a closure instead handler := func(path string, info os.FileInfo, err error) error {return t.walk(path, info, err)} _ = filepath.Walk(".", handler) } func (t myType) walk(path string, info os.FileInfo, err error) error { // do some heavy stuff on t and paths fmt.Println(t, path) return err } 

Func main() triggers walk() and due to the receiver t - walk() , I cannot find another way than using this ugly closure handler as an argument before filepath.Walk() . I would hope for something more fileWalk(".", t.walk) , but this does not work. This gives a compilation error "t.walk method is not an expression, should be called"

I believe that the solution for my closure is correct in this regard, or there are better options that I do not know about.

PS. This is one of several cases where I have to use this closure construct to pass a handler function that has a receiver. So, this question is more related to passing handler functions, not to filepath behavior.

Thanks for your suggestions.

+4
source share
2 answers

It's impossible.

In Go, methods are basically syntactic sugar; the receiver is actually the first parameter of the function. myType.walk has the signature func(myType, string, os.FileInfo, error) error . You can see this when trying to pass myType.walk to filepath.Walk instead of t.walk.

+4
source

While you mention ignoring the behavior of the file path for the question, the examples given depend heavily on it.

First, for addressing in a method, try defining an interface.

main package

 import ( "fmt" ) type Foo interface { Bar(a string) } type myFoo bool func (b myFoo) Bar(a string) { fmt.Println(b, a) } func exec(f Foo) { f.Bar("hello from exec") } func main() { var test myFoo exec(test) } 

So, in the example above, instead of trying to go through test.Bar before exec , you are actually defining an interface that describes what functionality is then passed to test .

In the case of filepath.Walk, it does not define an interface and instead expects the type of the function as an argument. In this case, you will need to wrap your method with the type func filepath.WalkFunc

Perhaps you can add an extra method to your type if you need to do this a lot (not verified)

 func (t myType) handlerFunc() filepath.WalkFunc { return func(path string, info os.FileInfo, err error) error { return t.walk(path, info, err) } } 

Then call filepath.Walk(".", t.handlerFunc())

+1
source

Source: https://habr.com/ru/post/1442302/


All Articles