How to specify the package name if multiple files exist in the package folder and one file contains the "package main"?

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

How to specify the package name if multiple files exist in the package folder and one file contains the "package main"?

问题

假设我有一个如下所示的包文件夹:

hello
  |---main.go
  |---utilities.go

main.go 中,我有:

package main

utilities.go 中,我有:

package hello

我这样做是因为:

  • 我不想把所有的工具都放在单个的 main.go 文件中。
  • 而且这些工具只被这个包使用,所以我不想把它放在 hello 文件夹之外。

但是当我运行 go list hello 时,它给出了这个结果:

> 无法加载包:包 hello 中找到了 main (main.go) 和 hello (utilities.go)

然后我移除了 utilities.go,只用 main.go 再次运行 go list hello,它给出了这个结果:

> hello

所以我是否必须将所有的工具移动到另一个包文件夹中?

我是否必须只保留 hello 包文件夹中的单个 main.go,因为它似乎与其他包名不兼容?

附加说明 1

一个有用的参考链接:http://thenewstack.io/understanding-golang-packages/

附加说明 2

经过一些简短的实验,我猜测 import yyy 决定了链接搜索路径,而 package xxx 声明则决定了编译后 .a 文件中的导出符号名称。

因为我注意到了以下事实:

  • package xxx 声明不必与包含的包文件夹名称相同,比如 yyy
  • 但是 import yyy 声明必须使用包文件夹路径 yyy
  • 当使用包中的符号时,我们仍然必须使用 xxx.Symbol 而不是 yyy.Symbol

附加说明 3

为了确认我在附加说明 2 中的猜测,我做了以下操作:

(pkg1\file1.go)

package pkg2 // 我故意使用了一个不同的包名 "pkg2" 而不是文件夹名 "pkg1"

import "fmt"

func FA() {
    fmt.Println("in the pkg2.FA")
}

(cmd1\main.go)

package main

import "pkg1"

func main() {
    pkg2.FA() // 这里,FA 是通过 "pkg2" 而不是 "pkg1" 引用的。
}

上述两个文件可以编译和运行。

但是如果我改成这样:

(cmd1\main.go)

package main

import "pkg1"

func main() {
    pkg1.FA() // 这里,FA 是通过 "pkg1",与导入语句中一致。应该可以工作,不是吗?
}

这将会报错:

>....\src\cmd1\main.go:3: imported and not used: "pkg1" as pkg2
>
>....\src\cmd1\main.go:6: undefined: pkg1 in pkg1.FA

为了再次确认,我使用 go tool nm pkg1.a 检查了编译后的 pkg1.a 文件,我没有看到包名影响导出的符号。(顺便说一下,GNU nm 工具似乎无法识别 golang 的 .a 文件格式。)

     U
 515 T %22%22.FA   <========== 这是我的函数 FA
 67b R %22%22.FA·f <========== 这是我的函数 FA
 5eb T %22%22.init
 67b B %22%22.initdone·
 683 R %22%22.init·f
     U fmt.Println
     U fmt.init
 673 R gclocals·33cdeccccebe80329f1fdbee7f5874cb
 66b R gclocals·69c1753bd5f81501d95132d08af04464
 65b R gclocals·e29b39dba2f7b47ee8f21f123fdd2633
 64d R go.string."in the pkg2.FA"
 63d R go.string.hdr."in the pkg2.FA"
 7d2 R go.typelink.*[1]interface {}
 796 R go.typelink.[1]interface {}
 737 R go.typelink.[]interface {}
     U runtime.algarray
     U runtime.convT2E
 6ec R runtime.gcbits.01
 68b R runtime.gcbits.03
     U runtime.morestack_noctxt
     U runtime.throwinit
 79a R type.*[1]interface {}
 7d6 R type..importpath.fmt.
 73b R type..namedata.*[1]interface {}.
 6ed R type..namedata.*[]interface {}.
 68c R type..namedata.*interface {}.
 74e R type.[1]interface {}
 6ff R type.[]interface {}
 69c R type.interface {}
     U type.string

所以目前的结论是:

当声明的包名与包文件夹名称不同时,包声明将被用作包的替代名称。

相当于这样,但是隐式地:

import pkg2 "pkg1"

顺便说一下,由于包声明在编译后的 .a 文件中没有反映出来,我猜测 golang 编译需要存在 .go 文件。

英文:

Suppose I have a package folder as below:

hello
  |---main.go
  |---utilities.go

In the main.go, I have:

package main

In the utilities.go, I have:

package hello

I did this because:

  • I don't want to put all the utilities into the single main.go file.
  • And the utilities are only used by this package so I don't want to put it out of the hello folder.

But when I run go list hello, it gives me this:

> can't load package: package hello: found packages main (main.go) and
> hello (utilities.go) in E:\Workbench\Go\src\hello

Then I remove the utilities.go and tried the go list hello again with only main.go. It gives me this:

> hello

So do I have to move all the utilities to another package folder?

Do I have to keep only the single main.go in the hello package folder because it seems it doesn't get along well with other package names?

ADD 1

An useful ref: http://thenewstack.io/understanding-golang-packages/

ADD 2

After a few brief experiments, I guess the import yyy decides the link search path while the package xxx declaration decides the exported symbol name in the compiled .a file.

Because I noticed these facts:

  • The package xxx declaration doesn't have to be the same as the containing package folder name, say yyy.
  • But the import yyy declaration must use the package folder path yyy.
  • When using a symbol from a package, we must still use the xxx.Symbol rather than yyy.Symbol.

ADD 3

To confirm my guess in ADD 2, I did this:

(pkg1\file1.go)

package pkg2 // I deliberately use a different pkg name "pkg2" rather than the folder name "pkg1"

import "fmt"

func FA() {
	fmt.Println("in the pkg2.FA")
}

(cmd1\main.go)

package main

import "pkg1"

func main() {
	pkg2.FA() //here, the FA is referenced via "pkg2" rather than the "pkg1".
}

The above 2 files can compile and run.

But if I changed to this:

(cmd1\main.go)

package main

import "pkg1"

func main() {
	pkg1.FA() //here, the FA is referenced via "pkg1" as in the import statement. Should work, isn't it?
}

This will give:

>....\src\cmd1\main.go:3: imported and not used: "pkg1" as pkg2
>
>....\src\cmd1\main.go:6: undefined: pkg1 in pkg1.FA

And to double confirm, I checked the compiled pkg1.a file with go tool nm pkg1.a, I didn't see package name affects the exported symbols. (btw, the GNU nm tool seems not be able to recognize the golang .a file format.)

     U
 515 T %22%22.FA   <========== this is my fuction FA
 67b R %22%22.FA·f <========== this is my fuction FA
 5eb T %22%22.init
 67b B %22%22.initdone·
 683 R %22%22.init·f
     U fmt.Println
     U fmt.init
 673 R gclocals·33cdeccccebe80329f1fdbee7f5874cb
 66b R gclocals·69c1753bd5f81501d95132d08af04464
 65b R gclocals·e29b39dba2f7b47ee8f21f123fdd2633
 64d R go.string."in the pkg2.FA"
 63d R go.string.hdr."in the pkg2.FA"
 7d2 R go.typelink.*[1]interface {}
 796 R go.typelink.[1]interface {}
 737 R go.typelink.[]interface {}
     U runtime.algarray
     U runtime.convT2E
 6ec R runtime.gcbits.01
 68b R runtime.gcbits.03
     U runtime.morestack_noctxt
     U runtime.throwinit
 79a R type.*[1]interface {}
 7d6 R type..importpath.fmt.
 73b R type..namedata.*[1]interface {}.
 6ed R type..namedata.*[]interface {}.
 68c R type..namedata.*interface {}.
 74e R type.[1]interface {}
 6ff R type.[]interface {}
 69c R type.interface {}
     U type.string

So the conclusion so far is:

When the declared package name is different from the package folder name, package declaration will be used as an alternate name of the package.

Equivalent to this, but implicitly :

import pkg2 "pkg1"

And btw, since the package declaration is not reflected in the compiled .a file, I guess the golang compilation requires the presence of .go file.

答案1

得分: 5

在同一个包(也就是文件夹)中的Go文件必须具有相同的包名。唯一的例外是测试文件,可以使用"_test"扩展名。规则是一个文件夹对应一个包,因此在同一个文件夹中的所有Go文件必须具有相同的包名。

答案是,是的,将"hello"包的文件移动到它们自己的文件夹中,或者在同一个目录中的所有文件中使用相同的包名。

英文:

go files in the same package AKA folder must have the same package name. The only exception are tests that can have a _test extension. The rule is 1 folder , 1 package therefore the same package name for all go files in the same folder.

The answer is yes , move the "hello" package files to their own folder or , use the same package name for all files in the same directory.

huangapple
  • 本文由 发表于 2016年11月29日 22:27:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/40868340.html
匿名

发表评论

匿名网友

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

确定