0

Go での関数変数の通常の使用では、変数同士ではなく、nil とのみ比較できます。この理由は (私に説明されているように)、Go にはクロージャーがあるため、平等の定義が曖昧だからです。ローカル変数にバインドされた異なる値を持つ 2 つの異なるクロージャがあり、それらが同じ基になる関数を使用している場合、それらは等しいか等しくないと見なされるべきですか?

しかし、私はそのような比較をできるようにたいと思っています。具体的には、次のようなコードがあります (ただし、実際のコードではチェックが実際に必要です。これは単なるダミーの例です)。ここでは、関数ポインターを関数リテラルと比較します。

func getFunc(which bool) (func ()) {
    if which {
        return func1
    } else {
        return func2
    }
}

func func1() { }
func func2() { }

f := getFunc(true)
if f == func1 {
    fmt.Println("func1")
} else {
    fmt.Println("func2")
}

たとえば、reflectまたはunsafeパッケージを使用して、これを機能させる方法はありますか?

4

3 に答える 3

2

@Lukeの答えを拡張すると、ポインターの等価性を直接テストできるようです。これは本当に不確かであることに注意してください。reflect.Value.Pointer()ドキュメントを引用するには:

v の Kind が Func の場合、返されるポインターは基になるコード ポインターですが、単一の関数を一意に識別するには必ずしも十分ではありません。唯一の保証は、v が nil func 値である場合に限り、結果がゼロになることです。

とはいえ、できることは次のとおりです。

f := getFunc(true)
f1 := reflect.ValueOf(f).Pointer()
f2 := reflect.ValueOf(func1).Pointer()
eq := f1 == f2

この新しいバージョンに対して一連のテスト (@Luke の回答から得られたコードの回帰テストに使用したもの) を実行したことに注意してくださいreflect。無視しても問題ありませんが、ドキュメントを無視することは決して良い考えではありません...

于 2013-08-08T01:23:22.503 に答える
1

比較したいすべての関数が同じシグネチャを持っている場合は、次のようにすることができます。

type cmpFunc struct {
    f func()
    id uint64
}

func (c *cmpFunc) call() { c.f() }
func (c *cmpFunc) equals(other *cmpFunc) { return c.id == other.id }

makeComparable(f func()) *cmpFunc {
    return &cmpFunc{f, get_uniq_id()}
}

箱に書かれていることはどこget_uniq_idで行われますか。Goにはオーバーロードがないため、これは少し醜く()なります。一般的な関数に対してこれを行いたい場合、ジェネリックなしでは多かれ少なかれ不可能です。しかし、これはあなたの目的にはかなりうまくいくはずです。

于 2013-08-05T21:51:22.230 に答える