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

1
2
3
hello
  |---main.go
  |---utilities.go

main.go中,我有:

1
package main

utilities.go中,我有:

1
package hello

我这样做是因为:

  • 我不想将所有实用程序放入单个main.go文件中。
  • 并且实用程序仅由此程序包使用,因此我不想将其从hello文件夹中删除。

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

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

然后我删除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

为了证实我在ADD 2中的猜测,我这样做了:

(以pkg1 file1.go)

1
2
3
4
5
6
7
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)

1
2
3
4
5
6
7
package main

import"pkg1"

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

以上2个文件可以编译运行。

但如果我改为:

(CMD1 main.go)

1
2
3
4
5
6
7
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?
}

这将给出:

....\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文件格式。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
     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

所以到目前为止的结论是:

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

相当于此,但隐含地:

1
import pkg2"pkg1"

顺便说一句,因为包声明没有反映在已编译的.a文件中,我想golang编译需要存在.go文件。

  • 请参见如何编写Go代码
  • 顺便说一句:将实用程序函数保存在文件utilities.go中并且仍在package main下是完全正常的。 Go中的包通常由几个文件组成,通常包含几种类型。

go文件在同一个包中AKA文件夹必须具有相同的包名。 唯一的例外是可以具有_test扩展的测试。 规则是1个文件夹,1个包因此同一个文件夹中所有go文件的包名称相同。

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

  • 你真的是指将"utilities.go"移动到另一个文件夹吗? 让文件夹只保存main.go文件的文件夹看起来很笨重。
  • utilities.go不是一个包的文件。 重要的是文件中的包名,你不能在同一个文件夹中有一个"hello"和一个"main"包并构建你的代码,这就是全部,这不是一个意见,这就是Go的工作方式。
  • 我想我可以将package main放入utilities.go并仍然将其保存在与main.go相同的文件夹中。 Go仍将通过名称main找到入口点。
  • 事实证明,内置的cmd\cgo包确实为同一个包文件夹中的所有*.go文件放置了package main
  • 并没有真正改变你的问题。 一个文件夹中只有一个包。 我不管包裹的名称是什么。 你不能在同一个文件夹中有2个包。