2015-04-20 20 views
7

ich vor kurzem eine Karte in einem meiner golang Projekte verwendet, die Funktionszeiger als Schlüssel wie folgt hatte:Karte mit Funktionszeiger als Schlüssel in go

map[*functiontype] somestructtype 

Einer meiner Kollegen sagte dies eine schlechte Idee war, Jetzt bin ich mir nicht sicher, ob das machbar ist. Ich hielt es zunächst für OK, weil Methodenzeiger auf Gleichheit überprüft werden können und unveränderbar sind. Kann jemand etwas dazu beitragen?

Komplettes Beispiel:

package main 

import "fmt" 

type s struct { 
    string 
} 

type f func() string 
func func1() string { return "func 1" } 
func func2() string { return "func 2" } 

func main() { 
    // make two functions and two pointers to them 
    f1, f2 := func1, func2 
    p1, p2 := (*f)(&f1), (*f)(&f2) 

    // make a map of their function pointers 
    m := make(map[*f]s) 
    m[p1] = s{"struct 1"} 
    m[p2] = s{"struct 2"} 

    // print out the mapping 
    printmapping(m, p1, p2) 

    // reverse the pointers and have that printed 
    p1, p2 = (*f)(&f2), (*f)(&f1) 
    printmapping(m, p1, p2) 
} 

func printmapping(m map[*f]s, p1, p2 *f) { 
    fmt.Println("pointer 1:", m[(*f)(p1)]) 
    fmt.Println("pointer 2:", m[(*f)(p2)]) 
} 

Antwort

4

Wenn der Schlüsseltyp ist ein Zeiger zu einem Funktionstyp (wie *func()), dann ist es völlig in Ordnung und die Semantik ist wie erwartet: gleich Zeiger sind gleich Tasten.

Das Nachschlagen der Werte in der Karte funktioniert jedoch möglicherweise nicht wie erwartet: example. Hier nimmt &f die Adresse der lokalen Variablen an, die für verschiedene Aufrufe von Add und Find nie dieselbe ist. Im Folgenden natürlich nützlich sein könnte: http://play.golang.org/p/F9jyUxzJhz


Wenn es nicht ein Zeiger ist, ist es eine schlechte Idee, weil es von Go 1 ab unmöglich ist. Entsprechend der Sprachspezifikation (live demo):

Die Vergleichsoperatoren == und! = Müssen für Operanden des Schlüsseltyps vollständig definiert sein; Daher darf der Schlüsseltyp keine Funktion, Map oder Slice sein.

== und != sind nicht für die Funktionen definiert, da das Problem Funktionen für Gleichheit zu vergleichen ist unentscheidbar.

+0

Leider hatte ich weggelassen ursprünglich das Sternchen vor Function in meinem Beispiel. Also wäre das obige (gerade editiert) wirklich in Ordnung? –

+0

@PeterHommel Da ist nichts technisch falsch, obwohl man sich kaum vorstellen kann, warum man einen Zeiger auf eine Funktion haben möchte. Welches Problem, denkst du, braucht diese Umleitung? Beachten Sie, dass Zeiger auf Funktionen in Go nicht mit Funktionszeigern in C identisch sind. Sie wären den Zeigern von Funktionszeigern in C ähnlicher. – rightfold

+0

Ich habe sie als Handler-Callbacks in einem Plugin-System verwendet. Ich wollte nur einige Daten von außen an jede Instanz dieses Callbacks anhängen und verwendete daher diese Art von Konstrukt. –

3

Ihre Frage ist zu abstrakt, um sinnvoll zu sein. Gib uns Code für ein echtes Beispiel. How to create a Minimal, Complete, and Verifiable example..

Zum Beispiel meinen Sie so etwas?

package main 

import "fmt" 

type f func(int) int 

type s struct{ i int } 

func f1(i int) int { return i } 

func f2(i int) int { return i * i } 

func main() { 
    p1, p2 := f1, f2 
    fmt.Println(p1, &p1, p2, &p2) 
    m := make(map[*f]s) 
    m[(*f)(&p1)] = s{f1(42)} 
    m[(*f)(&p2)] = s{f2(42)} 
    fmt.Println(m) 
    p1, p2 = f2, f1 
    fmt.Println(m) 
    fmt.Println(p1, &p1, p2, &p2) 
} 

Ausgang:

0x20000 0x1040a120 0x20020 0x1040a128 
map[0x1040a120:{42} 0x1040a128:{1764}] 
map[0x1040a128:{1764} 0x1040a120:{42}] 
0x20020 0x1040a120 0x20000 0x1040a128 
+1

Nicht genau, was ich meinte, aber ein guter Ausgangspunkt für ein komplettes Beispiel. Ich habe es einfach neu geschrieben, damit id meiner beabsichtigten Frage entspricht und es in meine Frage aufgenommen hat. Danke... –

Verwandte Themen