2016-03-21 29 views
2

を取得反映golangは、閉鎖関数ポインタ

package main 
import (
    "fmt" 
    "reflect" 
) 
func main() { 

    factory := func (name string) func(){ 
     return func(){ 
      fmt.Println(name) 
     } 
    } 
    f1 := factory("f1") 
    f2 := factory("f2") 

    pf1 := reflect.ValueOf(f1) 
    pf2 := reflect.ValueOf(f2) 

    fmt.Println(pf1.Pointer(), pf2.Pointer()) 
    fmt.Println(pf1.Pointer() == pf2.Pointer()) 

    f1() 
    f2() 
} 

結果コードを確認してください:

4199328 4199328 
true 
f1 
f2 

なぜ閉鎖機能の同じアドレスを取得します! または一意のアドレスを取得する方法へ!

答えて

3

機能ポインタは、機能のコードを示す。また、関数リテラルによって作成された無名関数のコードは、無名関数の値を返すコードが何回実行されても、メモリに一度だけ格納されます。つまり、すべての関数値(より正確には関数ポインタ)は同じになります。

f1f2に格納されている値を区別することはできません。これらは呼び出されたときに実行される同じコードブロックを示します。

変数factoryに格納されている関数値によって返される関数値はクロージャです。それが参照する環境(ローカル変数と関数パラメータ)は、アクセス可能な限り存続します。あなたの場合、これは、f1f2の関数値は、囲み匿名関数の引数であるnameを参照しているため、関数値(f1f2)がある限り、複数の呼び出しからのそれらの値アクセス可能なこれは、それらを「異なる」またはユニークにする唯一のものですが、これは「外部」からは見えません。

はあなたが先に行くと閉鎖にnameのアドレスを印刷し、あなたはそれが同じ場合同じクロージャ(関数である彼らは、複数の閉鎖の値は、しかしごとに異なる変数です参照してくださいね値)が再び呼び出されます。 f1f2複数回

factory := func(name string) func() { 
    return func() { 
     fmt.Println(name, &name) 
    } 
} 

およびコール:

f1() 
f2() 
f1() 
f2() 

出力:

f1 0x1040a120 
f2 0x1040a130 
f1 0x1040a120 
f2 0x1040a130 

あなたが見ることができるように、nameを第一にもnameのアドレスを印刷するクロージャを変更引き数が保持され、同じクロージャーが再度呼び出された場合は同じname引き数が再度使用されます。

+0

この質問と回答は非常に興味深いものでした。私はhttp://stackoverflow.com/q/9643205/1103700同様の質問(しかし、閉鎖についてではない)と答え啓発を発見した。 Goデザイナーは、機能やクロージャの比較を望んでいないように思えました。だから、Goデザイナーが私が期待していたのと同じように、人々が思いついたいくつかの回避策があります。 – WeakPointer

3

https://golang.org/pkg/reflect/#Value.Pointer

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