20

関数はfilepath.Walk関数コールバックを受け取ります。これは、コンテキスト ポインターのない単純な関数です。確かに、 の主な使用例Walkは、ディレクトリをたどって、より広いコンテキスト (各ファイルをテーブルに入力するなど) を参照して、それに基づいて何らかのアクションを実行することです。

これを C# で記述している場合、オブジェクト (コンテキスト内のオブジェクトを指すことができるフィールドを含む) をコールバック (特定のコールバック メソッドを使用) として使用し、オブジェクトがWalk呼び出し元のコンテキストをカプセル化できるようにします。

(編集:ユーザー「usr」は、C#でもクロージャメソッドが発生することを示唆しています)

これを C で記述している場合、関数とコンテキスト ポインターを として要求します。そのため、関数には、関数に渡してコールバック関数に渡さvoid *れたコンテキスト ポインターを取得できます。Walk

しかし、Go には関数引数しかなく、明らかなコンテキスト ポインター引数はありません。

(私がこの関数を設計していたら、オブジェクトを関数ではなくコールバックとして取り、インターフェイスなどに準拠し、そのインターフェイスにメソッド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
}

この例では、コールバック関数を作成して、そのクロージャーに変数numScannedmyStorageThing.

これは私には間違っているように感じます。奇妙に感じると思うのは正しいですか、それとも Go を書くことに慣れてきたのでしょうか? filepath.Walkコールバックがより広いコンテキストへの参照を持つような方法でメソッドを使用することは、どのように意図されていますか?

4

2 に答える 2

16

あなたはそれをほぼ正しくやっています。考えられる小さなバリエーションが 2 つあります。1 つは、未使用のパラメーターの名前をアンダーバーに置き換えることができることです。したがって、パスのみを使用した例では、署名は読み取ることができます

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

これにより、タイピングが少し節約され、コードが少しきれいになり、パラメーターを使用していないことが明確になります。また、特に小さな関数の場合、関数リテラルを変数に代入するのをスキップして、引数として直接使用するのが一般的です。あなたのコードは最終的に読み取り、

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

    myStorageThing.DoSomething(path)
})

これにより、スコープが少しクリーンアップされ、クロージャを 1 回だけ使用していることが明確になります。

于 2012-07-05T16:32:04.723 に答える
0

C# プログラマーとして、.NET でこのようなAPIを使用する方法はまさにこれだと言えます。時間を無駄にするだけなので、クロージャーを使用することをお勧めしますが、フィールドを持つ明示的なクラスを作成することはお勧めしません。

Go はクロージャをサポートしているので、これがこの API の正しい使い方だと思います。私はそれで何も悪いとは思いません。

于 2012-07-04T22:39:15.377 に答える