英文:
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()
,由于接收器t
到walk()
,我找不到其他方法,只能使用这个丑陋的闭包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 (
"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 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(".", t.handlerFunc())`
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论