I just started using Go for a simple web programming project, but I can't quite figure out how to accomplish simple pre-computation local to a single function. This is something I do quite frequently in OCaml, e.g.:
(* 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]
For those unfamiliar with OCaml, what's happening above is I'm binding the name render_page
to a function that takes two parameters and presumably returns a web page, but internally I'm first creating a local binding to templ
(this binding is only visible within the definition of render_page
, and the computation only happens once) and then using that binding within an anonymous function, which is the actual value bound to render_page
. So when you call render_page
, templ
isn't recompiled every time: it's just fetched from the closure environment.
Is there a common pattern for accomplishing something like this in Go? I'd like to avoid global variables as much as possible. I'm aware that "global" variables may be confined to a package's name space, which is what I'm currently doing, but I'd like to restrict the visibility of these precomputed expressions to just the functions in which they're needed.
Thanks!
Not familiar with Ocaml so not 100% sure if this Go example is what you are looking for, but you can define a function in Go which can pre-calculate some stuff and then return an anonymous function that internally uses the pre-calculated values.
For example, if you do this:
func matcher(pattern string) func(string) bool {
regExp := regexp.MustCompile(pattern)
return func(s string) bool {
return regExp.MatchString(s)
}
}
And then create one of these functions by doing:
myMatcher := matcher("123")
You can then call myMatcher("something")
multiple times, and the regexp expression will not be compiled each time since it was already compiled when calling the matcher
function.
Here's a working Go playground with this:
I think a closure (similar to what @eugenioy already answered with) is the closest you are going to get.
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)
}
}
OUTPUT
template is created
user: sberry, group: StackOverflow
user: user1030453, group: StackOverflow
In addition to the other answers here, note that once you define a closure, you can bind it to a global variable and treat it like other functions. Here is eugenioy's answer slightly modified :
var scan = matcher("123")
func main() {
fmt.Println(scan("456"))
fmt.Println(scan("123"))
}
Here, scan
is a global closure, which is very close to what you did in OCaml.