1、包声明:文件所在目录,有利于源码整体迁移。
2、包导入:4种方式。
----------------------------------------------------------------------------------------------------------------------------------
1、同一文件夹下面的所有源文件的所属包只能是同一个包名字,且最好是该目录名称。举例说明如下:
在imooc文件夹下有go源文件a.go,b.go,c.go,d.go,...等,那么所有这些go源文件中的第一行(非注释行)都是package XXX,而且最好就是:package imooc
在xiaomi文件夹下有go源文件x.go,y.go,z.go,w.go,...等,那么所有这些go源文件中的第一行(非注释行)都是package YYY,而且最好就是:package xiaomi
当然,将上面的package imooc与package xiaomi互换,即imooc文件夹下面的所有go源文件所属包为xiaomi,而xiaomi文件夹下面的所有go源文件所属包为imooc,也可以,但是这样的做法是一种智障,愚蠢,反人类的。
golang中的包如同其它一些编程语言中的类库或命名空间的概念。包是go的编译和安装的基本单元。每个go源文件必须首先声明自己属于哪个包,表明归属立场。
1、一个包下面的所有go源码文件的所属包最好都是该包名,而一个包下面的go源文件的文件名可以和包名相同,可以不同,即文件名没有约束。
2、go源文件:必须在go源文件中非注释的第一行指明该源文件属于哪个包,如:package main
。package main
表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main
的包。(go源文件所属包最好就是该文件所在的文件夹名称,最好一致,防止混乱)
(1)go源码文件分为三类:命令源码文件、库源码文件和测试源码文件。测试源码文件是来测试前两者的。如果一个go源码文件是声明自己属于main包,且该文件中有一个无参数无返回值的函数名称为imain的函数,则该文件叫做命令源码文件,是程序的入口,会生成可执行文件,会被安装到GOBIN指定的目录中。测试源码文件以“_test.go”命名,每个测试源码文件中至少有一个函数的名称是以“Test”或“Benchmark”为前缀的。其余的文件则是库源码文件。
(2)同一个main包中可以有多个命令源码文件,可通过go run来分别运行。但是此时无法通过go build编译该包,且也无法通过go install安装该包。因此拒绝同一个main包中有多个命令源码文件。命令源码文件可以在存放在其他包中,但是声明还是属于main包,但是尽量避免。
(3)同一个mian包中可以同时有命令源码文件和库源码文件,但是此时无法正常通过go build编译该包,且也无法正常通过go install安装该包,因为一个软件或程序模块的启动入口只有一个。因此拒绝同一个main包中混合着库源码文件。
(4)
(5)根据上述可知,推荐:项目只有一个main包,且该包下面只有一个命令源码文件,最好命令源码文件的文件名就是mian。main包,main文件名,main函数,一条线。
3、所有的包名都应该使用小写字母。属于同一个包的源文件必须全部被一起编译,一个包即是编译时的一个单元,因此根据惯例,每个目录都只包含一个包
4、包的导入的写法。导入的包必须要被使用,否则无法构建程序。源码包中的多个init函数执行顺序不确定,因此,尽量最多一个init函数。
5、可见性规则。包级别的名字,当标识符(常量(const)、变量(var)、类型(type)、函数(func)、结构体(struct)等等)以一个大写字母开头,如:Add,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为包可导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 private )。(大写字母可以使用任何 Unicode 编码的字符,比如希腊文,不仅仅是 ASCII 码中的大写字母)。因此,在导入一个外部包后,能够且只能够访问该包中可导出的对象。当然被导入包的存放位置必须是在环境变量GOPATH中定义的工作目录下面,否则无法找到。
假设在包 pack1 中我们有一个变量或函数叫做 Thing(以 T 开头,所以它能够被导出),那么在当前包中导入 pack1 包后,Thing 就可以像面向对象语言那样使用点标记来调用:pack1.Thing
(pack1 在这里是不可以省略的)。
因此包也可以作为命名空间使用,帮助避免命名冲突(名称冲突):两个包中的同名变量的区别在于他们的包名,例如 pack1.Thing
和 pack2.Thing
。当然,你可以通过使用包的别名来解决包名之间的名称冲突,或者说根据你的个人喜好对包名进行重新设置,如:import fm "fmt"
。
package main
import fm "fmt"
func main() {
fm.Println("hello, world")
}
6、一个程序必须有一个main包,main包中必须有一个源文件中含有一个main函数,且main函数既没有参数,也没有返回类型。
7、每个包都对应一个独立的名字空间。例如,在image包中的Decode函数和在unicode/utf16包中的 Decode函数是不同的。要在外部引用该函数,必须显式使用image.Decode或utf16.Decode形式访问。
8、包的初始化。以导入声明的顺序初始化,按照包依赖关系初始化,main包最后被初始化,且每个包只会被初始化一次。每个包的初始化是按照包中的init函数首先被初始化,然后按照先后顺序初始化包。
8、尽量在main包下面只写一个含有main函数的go源文件即可。
解决main包中源文件不能相互之间调用,如下main包中的main.go文件不能调用main包中的test.go文件,这是因为goland软件默认按照以文件为单位编译,因此也就默认编译了man函数所在的main.go文件,如下:
那么就需要修改goland软件的编译方式,有三种选择,分别是File,Package,Directory。那么选择为Package包方式编译,写好包路径即可,如下:view----Toolbar,然后找到edit configurations即可调节。
设置好后,不要用快捷键ctrl+shift+f10来启动程序,因为这个快捷键就是按照文件来的,而是用shift+f10,或者用最上面的按钮,按钮如下图:
那么如果在命令行上启动呢?效果如下:
#go run main.go,则不能正常编译,要用go run *.go
因此,为了避免这样的麻烦,尽量在main包下面只写一个含有main函数的go源文件即可。