Description
It's often more convenient to use a for loop rather than a callback-based API, and fs.WalkDir and filepath.Walk are both callback-based APIs. I've been using github.com/kr/fs for years to work around this.
The new iterate-over-func functionality (#61405) now makes it straightforward to adapt the stdlib functions into iterators, so perhaps we could provide iterator-based APIs as part of the standard library now.
Here's a straw-man implementation:
package fs
type WalkDirEntry struct {
Path string
Entry fs.DirEntry
Err error
skipDir *bool
}
// SkipDir causes the iteration to skip the contents
// of the entry. This will have no effect if called outside the iteration
// for this particular entry.
func (entry WalkDirEntry) SkipDir() {
*entry.skipDir = true
}
// WalkDirIter returns an iterator that can be used to iterate over the contents
// of a directory. It uses WalkDir under the hood. To skip a directory,
// call the SkipDir method on an entry.
func WalkDirIter(fsys fs.FS, root string) func(func(WalkDirEntry) bool) {
return func(yield func(WalkDirEntry) bool) {
fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
skipDir := false
info := WalkDirEntry{
Path: path,
Entry: d,
Err: err,
skipDir: &skipDir,
}
if !yield(info) {
return fs.SkipAll
}
if skipDir {
return fs.SkipDir
}
return nil
})
}
}
The main point of contention from my point of view is the semantics of the SkipDir method. Calling a method on an iterated item to determine the subsequent course of iteration seems somewhat unusual, but I don't see any other decent alternative.
[Edited to remove incorrect remarks about GC behavior].
Metadata
Metadata
Assignees
Type
Projects
Status