2017-06-02 45 views
2

我刚开始使用Go进行简单的Web编程项目,但我无法完全弄清楚如何在单个函数中实现简单的预计算。这是我在OCaml中做的相当频繁,如:为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] 

对于那些不熟悉OCaml的,什么上面发生的是我的名字render_page结合,它有两个参数,想必返回网页的功能,但在内部,我首先创建了一个到templ的本地绑定(该绑定仅在render_page的定义中可见,并且计算仅发生一次),然后在匿名函数内使用该绑定,这是绑定到render_page的实际值。所以当你拨打render_page时,templ不会每次重新编译:它只是从闭包环境中获取。

在Go中有这样一个常见的模式吗?我想尽可能地避免全局变量。我意识到,“全局”变量可能局限于包的名称空间,这正是我目前正在做的,但我想限制这些预先计算的表达式的可见性仅限于它们所需的函数。

谢谢!

+1

Go没有函数本地静态变量。如果你想在一个函数的执行之间共享一个可变值,它必须是一个全局变量。您可以将函数局部常量用于不可变值,但常数仅限于内置类型。 – Adrian

+1

您也可以使变量成为结构体的成员,并根据您的用例将该函数转换为该结构体上的方法。您仍然需要确保重新使用该结构的同一个实例。就个人而言,我只会使用全球。 – Adrian

回答

2

不熟悉Ocaml所以不能100%确定这个Go示例是你在找什么,但是你可以在Go中定义一个函数,它可以预先计算一些东西,然后返回一个内部使用pre的匿名函数 - 计算值。

例如,如果你这样做:

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函数时都要进行编译。

这里有一个工作去操场这样的:

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

+0

您也可以将得到的闭包绑定到全局变量,然后您可以像使用其他函数一样使用它(请参阅我的答案)。 – coredump

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 
0

除了这里其他的答案,注意,一旦你定义一个关闭,你可以把它绑定到一个全局变量,并把它像其他的功能。 这里是eugenioy的answer略作修改:

var scan = matcher("123") 

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

这里,scan是一个全球性的关闭,这是非常接近你OCaml中做了什么。

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