我打算如何在Go中使用Filepath.Walk?

时间:2012-07-04 22:34:27

标签: closures go

filepath.Walk函数接受函数回调。这是直接函数,没有上下文指针。当然Walk的一个主要用例是走一个目录并根据它采取一些行动,参考更广泛的上下文(例如将每个文件输入到表中)。

如果我在C#中编写它,我会使用一个对象(可以指向上下文中的对象的字段)作为回调(使用给定的回调方法),因此该对象可以封装{ {1}}来自。

(编辑:用户“usr”表示闭包方法也在C#中发生)

如果我在C中写这个,我会要求一个函数和一个上下文指针作为Walk,所以该函数有一个上下文指针,它可以传递给void *函数并得到它传递给回调函数。

但Go只有函数参数,没有明显的上下文指针参数。

(如果我设计了这个函数,我会把一个对象作为一个回调而不是一个函数,符合接口Walk或其他什么,并在该接口上放置一个FileWalkerCallback方法。然后,消费者可以在将对象传递给callback(...)之前将任何上下文附加到对象。)

我能想到的唯一方法是捕获回调函数中外部函数的闭包。我正在使用它:

Walk

在这个例子中,我创建了回调函数,因此它的闭包包含变量func ScanAllFiles(location string, myStorageThing *StorageThing) (err error) { numScanned = 0 // Wrap this up in this function's closure to capture the `corpus` binding. var scan = func(path string, fileInfo os.FileInfo, inpErr error) (err error) { numScanned ++ myStorageThing.DoSomething(path) } fmt.Println("Scan All") err = filepath.Walk(location, scan) fmt.Println("Total scanned", numScanned) return } numScanned

这对我来说是错误的。我是否认为这感觉很奇怪,或者我只是习惯写Go?它是如何以myStorageThing方法的方式使用回调引用更广泛的上下文的方式?

2 个答案:

答案 0 :(得分:15)

你正确地做到了。您可以考虑两种小变化。一个是您可以用下划线替换未使用参数的名称。因此,在您仅使用路径的示例中,签名可以读取

func(path string, _ os.FileInfo, _ error) error

它节省了一点点打字,稍微清理了一下代码,并清楚地表明你没有使用该参数。此外,特别是对于小函数,通常跳过将函数文本赋值给变量,并直接将其用作参数。你的代码最终会阅读,

err = filepath.Walk(location, func(path string, _ os.FileInfo, _ error) error {
    numScanned ++

    myStorageThing.DoSomething(path)
})

这清理了一点范围,明确表示你只使用了一次封闭。

答案 1 :(得分:0)

作为一名C#程序员,我可以说这正是.NET中这样一个API 意味着的用法。我们鼓励您使用闭包并且不鼓励使用字段创建显式类,因为它只会浪费您的时间。

由于Go支持闭包,我认为这是使用此API的正确方法。我没有看到它有任何问题。