处理程序函数中的接收器,例如filepath.WalkFunc

huangapple go评论94阅读模式
英文:

Receivers in handler functions such as filepath.WalkFunc

问题

我遇到了一个小问题,只有一个有点丑陋的解决方案。
我无法想象我是第一个遇到这个问题的人,但我在SO上没有找到任何线索。

在下面(故意简化的)示例中,我想在walk函数上有一个接收器,这是我的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
}

函数main()触发walk(),由于接收器twalk(),我找不到其他方法,只能使用这个丑陋的闭包handler作为filepath.Walk()的参数。我本来希望有类似fileWalk(".", t.walk)的东西,但那样不起作用。它会给出编译错误“方法t.walk不是一个表达式,必须被调用”。

在这方面,我的闭包解决方案是正确的方法,还是有其他我不知道的更好的选择。

PS. 这是我不得不使用这个闭包结构传递一个具有接收器的处理程序函数的几个场合之一。因此,这个问题与传递处理程序函数而不是filepath行为更相关。

谢谢你的建议。

英文:

I've run into a small issue for which I have a bit of an ugly solution only.
I cannot imagine I'm the first, but I haven't found any clues on SO.

In the following (deliberately simplified) example I'd 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 because of the receiver t to walk(), I
cannot find another way than to use this ugly closure handler as an argument
to filepath.Walk(). I would have hoped for something more like
fileWalk(".", t.walk) but that does not work. It gives the compile error
" method t.walk is not an expression, must be called"

Is my closure solution the correct approach in this respect, or are there better options I don't know of.

PS. This is one of several occasions in which I have to use this closure construction
to pass a handler function which has a receiver. So, this question is more related
to passing handler functions than to filepath behaviour.

Thanks for you suggestions.

答案1

得分: 4

这是不可能的。

在Go语言中,方法大多是语法糖,接收器实际上是函数的第一个参数。myType.walk基本上具有func(myType, string, os.FileInfo, error) error的签名。当你尝试将myType.walk传递给filepath.Walk而不是t.walk时,你可以看到这一点。

英文:

This is not possible.

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

答案2

得分: 1

当你提到忽略filepath的行为时,给出的示例在很大程度上依赖于它。

首先,为了解决传递方法的问题,可以尝试定义一个接口。

package main

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)
}

所以在上面的例子中,不要试图将test.Bar传递给exec,而是实际上定义一个描述功能的接口,然后完整地传递test

在filepath.Walk的情况下,它没有定义一个接口,而是期望一个函数类型作为参数。在这种情况下,你需要用一个func类型filepath.WalkFunc包装你的方法。

如果你发现自己经常需要这样做,你可以为你的类型添加一个额外的方法(未经测试)。

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

然后调用`filepath.Walk(".", t.handlerFunc())`

<details>
<summary>英文:</summary>

While you mention ignoring the behavior of filepath for the question, the examples given are largely dependent on it.

First, to address passing in a method, instead try defining an interface.


package main

    import (
	    &quot;fmt&quot;
    )

    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(&quot;hello from exec&quot;)
    }

    func main() {
	    var test myFoo
	    exec(test)
    }

So in the above, instead of trying to pass in `test.Bar` to `exec`, you would actually define an interface that describes what functionality and then pass in `test` completely.

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

You could probably add an additional method to your type if you find yourself needing to do this alot (not tested)

    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(&quot;.&quot;, t.handlerFunc())`

</details>



huangapple
  • 本文由 发表于 2012年10月26日 20:28:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/13086943.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定