英文:
Precomputing simple values for a function in Go
问题
我刚刚开始使用Go进行一个简单的Web编程项目,但我无法弄清楚如何在单个函数中实现简单的预计算。在OCaml中,我经常这样做:
(* 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]
对于不熟悉OCaml的人来说,上面的代码是将名称render_page
绑定到一个接受两个参数并返回网页的函数,但在内部,我首先创建了一个局部绑定到templ
(此绑定仅在render_page
的定义中可见,并且计算仅发生一次),然后在匿名函数中使用该绑定,该匿名函数是实际绑定到render_page
的值。因此,当你调用render_page
时,templ
不会每次重新编译:它只是从闭包环境中获取。
在Go中是否有一种常见的模式可以实现类似的功能?我想尽量避免使用全局变量。我知道“全局”变量可能被限制在包的命名空间中,这是我目前正在做的,但我希望将这些预计算表达式的可见性限制在它们所需的函数中。
谢谢!
英文:
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!
答案1
得分: 1
对于不熟悉Ocaml的人来说,我不能百分之百确定这个Go示例是否符合你的要求,但你可以在Go中定义一个函数,该函数可以预先计算一些内容,然后返回一个内部使用预先计算值的匿名函数。
例如,你可以这样做:
func matcher(pattern string) func(string) bool {
regExp := regexp.MustCompile(pattern)
return func(s string) bool {
return regExp.MatchString(s)
}
}
然后通过以下方式创建一个这样的函数:
myMatcher := matcher("123")
你可以多次调用myMatcher("something")
,由于在调用matcher
函数时已经编译了正则表达式,所以正则表达式不会每次都重新编译。
这里有一个使用这种方法的Go Playground示例:
https://play.golang.org/p/m3vBrYn4Dg
英文:
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:
答案2
得分: 0
我认为闭包(类似于@eugenioy已经回答的内容)是你能得到的最接近的东西。
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)
}
}
输出
template is created
user: sberry, group: StackOverflow
user: user1030453, group: StackOverflow
英文:
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
答案3
得分: 0
除了这里其他的答案之外,还要注意一旦你定义了一个闭包,你可以将其绑定到一个全局变量,并像其他函数一样对待它。
这里是eugenioy的答案稍作修改:
var scan = matcher("123")
func main() {
fmt.Println(scan("456"))
fmt.Println(scan("123"))
}
在这里,scan
是一个全局闭包,非常接近你在OCaml中所做的。
链接:https://play.golang.org/p/Lc0SC53b-0
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论