GAE Go,init() – 可以多次调用吗?

huangapple go评论70阅读模式
英文:

GAE Go, init() - call it multiple times?

问题

我正在编写一个Google App Engine Go应用程序。在其中,我想要在不同的.go文件中分别处理一些调用。我应该在每个文件中单独调用"init()"函数,还是只在一个文件中声明它,并调用其他一些函数来初始化每个.go文件?

例如,如果我有两个文件,user.go:

package User

import(
	"http"
	"fmt"
)

func init() {
    http.HandleFunc("/", hello)
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, user!")
}

和admin.go:

package Admin

import(
	"http"
	"fmt"
)

func init() {
    http.HandleFunc("/admin/", hello)
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, admin!")
}

这样的初始化方式是正确的,还是不建议这样做?

英文:

I'm writing a Google App Engine Go application. In it, I want to handle some calls separately in different .go files. Should I call "init()" function separately in each of those files, or just declare it in one file and call some other functions for initialisation of each .go file?

For example, if I'd have two files, user.go:

package User

import(
	"http"
	"fmt"
)

func init() {
    http.HandleFunc("/", hello)
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, user!")
}

And admin.go:

package Admin

import(
	"http"
	"fmt"
)

func init() {
    http.HandleFunc("/admin/", hello)
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello, admin!")
}

Is such an initialisation correct, or is it advised against something like this?

答案1

得分: 10

根据Go语言规范:

  • 所有初始化代码在一个单独的goroutine中运行,并且

  • 在一个单独的包中的init()函数的执行顺序是未指定的

在你的情况下,包User和Admin是独立的(User不导入Admin,Admin也不导入User)。这意味着:

  • User和Admin中的两个init()函数的执行顺序是未指定的

将两个init()函数的内容合并为一个init()函数,代码如下:

func init() {
    http.HandleFunc("/", User.Hello)
    http.HandleFunc("/admin/", Admin.Hello)
}

注意,程序首先注册<code>"/"</code>或<code>"/admin/"</code>是无关紧要的。因此,以下代码也是有效的:

func init() {
    http.HandleFunc("/admin/", Admin.Hello)
    http.HandleFunc("/", User.Hello)
}

从上面的两段代码中,我们可以看到<code>http.HandleFunc("/", ...)</code>和<code>http.HandleFunc("/admin/", ...)</code>的调用顺序是未指定的。


因为<code>"/"</code>和<code>"/admin/"</code>可以以任何顺序注册,并且所有的init()函数都在一个单独的goroutine中运行,所以对于你的问题的答案是:是的,这样的初始化是正确的

英文:

According to Go language specification:

  • all initialization code is run in a single goroutine, and

  • init() functions within a single package execute in unspecified order

In your case, the packages User and Admin are independent (User does not import Admin, nor Admin imports User). This means that:

  • the two init() functions in User and Admin execute in unspecified order

Joining the bodies of the two init() functions in a single init() function would look like this:

func init() {
    http.HandleFunc(&quot;/&quot;, User.Hello)
    http.HandleFunc(&quot;/admin/&quot;, Admin.Hello)
}

Notice that it is irrelevant whether the program first registers <code>"/"</code> or <code>"/admin/"</code>. So, the following code is also valid :

func init() {
    http.HandleFunc(&quot;/admin/&quot;, Admin.Hello)
    http.HandleFunc(&quot;/&quot;, User.Hello)
}

From the above two snippets of code, we can see that it is OK for <code>http.HandleFunc("/", ...)</code> and <code>http.HandleFunc("/admin/", ...)</code> to be called in unspecified order.


Because <code>"/"</code> and <code>"/admin/"</code> can be registered in any order, and all init() functions run in a single goroutine, the answer to your question is: Yes, such an initialisation correct.

答案2

得分: 1

我认为你的问题实际上是关于包设计的问题。根据你的问题,我无法确定你是否混淆了包和源文件。为了澄清:一个包由一个或多个源文件组成,位于一个目录中,定义了一个包括公共API和私有内部数据表示的逻辑功能单元。

如果你对init()的具体内容感兴趣,以下是规范中相关的部分:

一个没有导入的包通过为其所有的包级变量分配初始值,然后调用其源文件中定义的名为func init()、具有相同签名的任何包级函数来进行初始化。

你在上面的代码中定义了两个包,所以下面的内容也适用:

如果一个包有导入,那么导入的包会在初始化该包本身之前进行初始化。

这意味着如果Admin对User有依赖(或反之亦然),这将决定两个init()调用的执行顺序。如果没有这样的依赖,init()调用的执行顺序将是未指定的。

然而,根据你的代码,你并不真正关心它们的执行顺序。所以实际上问题在于你是否真的需要两个包,或者你是否可以使用一个单独的包(可能有两个独立的源文件)。

你可以问自己一些问题:

  • 是否有两个独立的(业务)功能需要表示?
  • 是否需要提供独立的公共API?
  • 是否有组织上的原因需要将不同的包分开(不同的编码人员)?
  • 是否计划在一个或多个包中独立于其他包重用代码?
英文:

I think your question is really one of package design. I can't quite tell by your question, but you may also be confusing packages and source files. To clarify: a package is made up of one or more source files in one directory, defines a logical unit of functionality including public APIs and private internal representations of data.

If you are interested in the specifics of init(), here are the relevant portions of the spec

> A package with no imports is initialized by assigning initial values
> to all its package-level variables and then calling any package-level
> function with the name and signature of
>
> func init()
>
> defined in its source.

You have two packages defined in your code above, so the following also applies:

> If a package has imports, the imported packages are initialized before
> initializing the package itself.

Which suggests if there is a dependence of Admin on User (or vice versa) that will determine the order in which the two init() calls are executed. No such dependence will result in the execution of the init() calls in unspecified order.

However, given the code that you have, you don't really care in which order they execute. So really it comes down to whether you really need two packages or whether you could do with a single package (possibly with two separate source files).

Some questions you might ask yourself:

  • Are there two separate (business) functions to be represented?
  • Do you need to provide separate public APIs?
  • Any organizational reasons to separate different packages (different coders)?
  • Do you plan to reuse the code in one or more packages independent of the other?

huangapple
  • 本文由 发表于 2012年1月30日 11:50:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/9059129.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定