2015-04-20 16 views
7

Recentemente ho usato una mappa in uno dei miei progetti golang, che ha avuto i puntatori a funzione come tasti come questo:mappa con puntatore a funzione, come chiave per andare

map[*functiontype] somestructtype 

uno dei miei colleghi ha detto che questa era una cattiva idea, quindi ora non sono sicuro che questo sia fattibile. Inizialmente l'ho ritenuto ok, perché i puntatori del metodo possono essere controllati per l'uguaglianza e sono immutabili. Qualcuno può fornire un ragionamento su questo argomento?

Esempio completo:

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)]) 
} 

risposta

4

Se il tipo di chiave è un puntatore ad un tipo di funzione (come ad esempio *func()) allora è totalmente soddisfacente e la semantica sono come previsto: pari puntatori sono chiavi uguali.

Tuttavia, cercare i valori nella mappa potrebbe non funzionare come previsto: example. Qui &f prende l'indirizzo della variabile locale, che non è mai lo stesso per le diverse chiamate di Add e Find. Di seguito, naturalmente, potrebbe essere utile: http://play.golang.org/p/F9jyUxzJhz


Se è non un puntatore, è una cattiva idea, perché è impossibile da Go 1 in poi. In base alle specifiche della lingua (live demo):

Gli operatori di confronto == e! = Devono essere completamente definiti per gli operandi del tipo di chiave; quindi il tipo di chiave non deve essere una funzione, una mappa o una fetta.

== e != non sono definiti per funzioni poiché il problema delle funzioni confronto per uguaglianza è indecidibile.

+0

dispiace, avevo inizialmente omesso l'asterisco prima FunctionType nel mio esempio. Quindi quanto sopra (appena modificato) sarebbe davvero ok? –

+0

@PeterHommel Non c'è niente di tecnicamente sbagliato in questo, anche se è difficile immaginare perché si vorrebbe un puntatore a una funzione. Quale problema pensi che richieda questa indiretta? Nota che i puntatori alle funzioni in Go non sono gli stessi dei puntatori di funzione in C; sarebbero più simili ai puntatori ai puntatori alle funzioni in C. – rightfold

+0

Li ho usati come callback del gestore in un sistema di plugin. Volevo semplicemente allegare alcuni dati dall'esterno a ogni istanza di questo callback e quindi utilizzato questo tipo di costrutto. –

3

La tua domanda è troppo astratta per essere significativa. Dacci un codice per un esempio reale. How to create a Minimal, Complete, and Verifiable example..

Ad esempio, intendi qualcosa del genere?

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) 
} 

uscita:

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

Non esattamente quello che intendevo, ma un buon punto di partenza per un esempio completo. Basta riscriverlo per far sì che l'ID aderisca alla mia domanda prevista e la incorpori nella mia domanda. grazie... –

Problemi correlati