Подтвердить что ты не робот

Как я должен использовать Filepath.Walk в Go?

Функция filepath.Walk выполняет функцию обратного вызова функции. Это прямая функция без указателя контекста. Разумеется, основным вариантом использования Walk является прохождение каталога и принятие на нем определенных действий со ссылкой на более широкий контекст (например, ввод каждого файла в таблицу).

Если бы я писал это на С#, я бы использовал объект (с полями, которые могли бы указывать на объекты в контексте) в качестве обратного вызова (с заданным методом обратного вызова), чтобы объект мог инкапсулировать контекст, который Walk вызывается из.

(EDIT: пользователь usr" предполагает, что метод закрытия также встречается на С#)

Если бы я писал это на C, я бы попросил функцию и указатель контекста как void *, чтобы функция имела указатель контекста, который она может передать в функцию Walk, и передать ее в функция обратного вызова.

Но Go имеет только аргумент функции и не имеет очевидного аргумента указателя контекста.

(Если бы я разработал эту функцию, я бы взял объект как обратный вызов, а не функцию, соответствующую интерфейсу FileWalkerCallback или тому подобное, и поместил на этот интерфейс метод callback(...). Тогда потребитель мог бы присоедините любой контекст к объекту, прежде чем передавать его на Walk.)

Единственный способ, которым я могу это сделать, - захватить закрытие внешней функции в функции обратного вызова. Вот как я его использую:

func ScanAllFiles(location string, myStorageThing *StorageThing) (err error) {
    numScanned = 0

    // Wrap this up in this function 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 и myStorageThing.

Это кажется мне неправильным. Правильно ли я считаю, что это странно, или я просто привык писать "Go"? Как он предназначен для метода filepath.Walk для использования таким образом, чтобы обратный вызов ссылался на более широкий контекст?

4b9b3361

Ответ 1

Вы делаете это правильно. Есть два небольших варианта, которые вы могли бы рассмотреть. Во-первых, вы можете заменить имя неиспользуемого параметра на нижний план. Итак, в вашем примере, где вы использовали только путь, подпись могла читать

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

Это немного облегчает ввод, немного очищает код и дает понять, что вы не используете параметр. Кроме того, для небольших функций, в частности, это обычный пропуск, назначающий литерал функции переменной, и просто используйте его непосредственно в качестве аргумента. Ваш код заканчивается чтением,

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

    myStorageThing.DoSomething(path)
})

Это немного очищает область, давая понять, что вы используете закрытие только один раз.

Ответ 2

Как программист на С#, я могу сказать, что именно так будет использоваться такой API в .NET. Вам будет предложено использовать закрытие и не рекомендуется создавать явный класс с полями, потому что он просто тратит ваше время.

Как Go поддерживает закрытие, я бы сказал, что это правильный способ использования этого API. Я не вижу в этом ничего плохого.