2017-06-02 3 views
2

Je viens de commencer à utiliser Go pour un simple projet de programmation Web, mais je n'arrive pas à comprendre comment réaliser un simple pré-calcul local pour une seule fonction. Ceci est quelque chose que je fais assez souvent en OCaml, par exemple:Précalculer des valeurs simples pour une fonction dans Go

(* maybe render_page is a handler function for an HTTP server or something *) 
let render_page = 
    (* let's say that Template.prepare takes a template string and returns its compiled representation *) 
    let templ = Template.prepare "user: {{.}}, group: {{.}}" in 
    (* return an anonymous function *) 
    fun user group -> 
    templ [user; group] 

Pour ceux qui ne connaissent OCaml, ce qui se passe au-dessus est que je lient le nom render_page à une fonction qui prend deux paramètres et renvoie sans doute une page Web, mais interne je crée d'abord une liaison locale à templ (cette liaison est seulement visible dans la définition de render_page, et le calcul ne se produit qu'une seule fois) puis en utilisant cette liaison dans une fonction anonyme, qui est la valeur réelle liée à render_page. Ainsi, lorsque vous appelez render_page, templ n'est pas recompilé à chaque fois: il vient d'être extrait de l'environnement de fermeture.

Existe-t-il un modèle commun pour accomplir quelque chose comme ça dans Go? J'aimerais éviter autant que possible les variables globales. Je suis conscient que les variables "globales" peuvent être confinées à l'espace de nom d'un paquet, ce que je fais actuellement, mais je voudrais limiter la visibilité de ces expressions précalculées aux seules fonctions dans lesquelles elles sont nécessaires .

Merci!

+1

Go ne pas variables statiques fonction locale.Si vous voulez partager une valeur mutable entre les exécutions d'une fonction, il doit s'agir d'une variable globale. Vous pouvez utiliser des constantes fonction-locales pour les valeurs immuables, mais les constantes sont limitées aux types prédéfinis. – Adrian

+1

Vous pouvez également faire de la variable un membre d'une structure et convertir la fonction en méthode sur cette structure, en fonction de votre cas d'utilisation. Vous devez toujours vous assurer que la même instance de la structure a été réutilisée. Personnellement, je voudrais juste utiliser un global. – Adrian

Répondre

2

Vous n'êtes pas familier avec Ocaml, donc vous n'êtes pas sûr à 100% si cet exemple Go est ce que vous cherchez, mais vous pouvez définir une fonction dans Go qui peut pré-calculer et retourner une fonction anonyme qui utilise le pré -calculated values.

Par exemple, si vous faites ceci:

func matcher(pattern string) func(string) bool { 
    regExp := regexp.MustCompile(pattern) 
    return func(s string) bool { 
     return regExp.MatchString(s) 
    } 
} 

Et puis créez une de ces fonctions en faisant:

myMatcher := matcher("123") 

Vous pouvez ensuite appeler myMatcher("something") plusieurs fois, et l'expression de regexp ne être compilé chaque fois qu'il a déjà été compilé lors de l'appel de la fonction matcher.

est ici un terrain de jeu Go travailler avec ceci:

https://play.golang.org/p/m3vBrYn4Dg

+0

Vous pouvez également lier la fermeture résultante à une variable globale, puis vous pouvez l'utiliser comme d'autres fonctions (voir ma réponse). – coredump

0

Je pense qu'une fermeture (semblable à ce que @eugenioy déjà répondu avec) est le plus proche, vous allez obtenir.

func main() { 
    userGroupTemplate := renderPage() 
    fmt.Println(userGroupTemplate("sberry", "StackOverflow")) 
    fmt.Println(userGroupTemplate("user1030453", "StackOverflow")) 
} 

func renderPage() func(user, group string) string { 
    templ := "user: %s, group: %s" 
    fmt.Println("template is created") 
    return func(user, group string) string { 
     return fmt.Sprintf(templ, user, group) 
    } 
} 

SORTIE

template is created 
user: sberry, group: StackOverflow 
user: user1030453, group: StackOverflow 
0

En plus des autres réponses ici, notez qu'une fois que vous définissez une fermeture, vous pouvez le lier à une variable globale et de la traiter comme d'autres fonctions. Voici answer de eugenioy légèrement modifié:

var scan = matcher("123") 

func main() { 
    fmt.Println(scan("456")) 
    fmt.Println(scan("123")) 
} 

Ici, scan est une fermeture globale, ce qui est très proche de ce que vous avez fait en OCaml.

https://play.golang.org/p/Lc0SC53b-0