Go关键字--package

package

package用来定义包。golang源文件为什么需要声明包名?

golang语言通过目录来管理golang源文件(.go结尾文件),单个目录下边所有的golang源文件中定义的函数,变量,结构体等等形成了一个集合,包名就是这个集合的名字。在目录A中引用目录B中的变量,函数,结构体等时,首先需要在发生引用的golang源文件中导入B目录的路径,然后通过B目录中golang源文件声明的包名来访问B目录下的变量,函数,结构体等等。

在一个集合里边,重复的定义变量,函数,结构体等等是一种无效的行为,golang是一门注重简洁的语言,自然不会允许这种无效的代码出现,所以,在单个目录下边重复的定义变量,函数,结构体等等,在编译时会产生错误。

一个目录中,子目录包名需要与上级目录一样吗?
答案是:可以不一样,也可以一样。

toolbox
------tb1.go
------tb2.go
------tb3.go
------logs   (目录)
------cache  (目录)
------route  (目录)

如在GOPATH/src中存在一个目录toolbox,那么toolbox目录下的golang源文件中定义的包名是toolbox。在toolbox下边又存在3个目录,分别是logs,cache,route,这3个子目录中可以声明不同的包名。如目录logs中可以声明包名为logs,也可以声明为toolbox;目录cache中可以声明包名为cache,也可以声明为toolbox;目录route中可以声明包名为route,也可以声明为toolbox。也就是下级目录可以与上级目录声明不同的包名,也可以声明相同的包名。

不同目录中,声明同样的包名会出现覆盖嘛?
答案是:不会

golang代码中,在引用包时,导入的是包所在的目录路径,即使不同的目录采用了相同的包名,也不会产生冲突和覆盖。后续在import中详细的介绍包的引用。

下边创建一个示例工程,来详细的介绍package用法

workspace
---bin
---pkg
---src
------github.com
---------hzwy23
------------GoDemos
---------------demo1
------------------de1.go
------------------de2.go
------------------de3_test.go
---------------demo3
------------------de4.go
------------------de5.go
---------------demo2
------------------main.go
------------------demo2.go
------------------demo3.go
  1. 一个目录中,只能定义一个包名,如目录demo3中有两个文件,分别是de4.go和de5.go。这两个文件中定义包名必须相同。有一个情况除外,如果demo1目录中有一个golang文件为de3_test.go,de3_test.go中可以用de1.go或de2.go的包名加上“_test”作为包名,这个是golang test的一个特性,后续在单元测试中会重点讲解test,在此仅仅需要记住,一个目录中,只能定义一个包名(测试文件与子目录除外)。

如在demo1目录中,定义demo包,内容分别是:

de1.go文件

package demo

import (
    "fmt"
)

func Demo1() {
    fmt.Println("hello demo1")
}

de2.go文件

package demo

import (
    "fmt"
)

func Demo2() {
    fmt.Println("hello demo2")
}

de3_test.go文件

package demo_test

import (
    "fmt"
)

func TestDemo() {
    fmt.Println("test demo")
}
  1. 如果包被主程序直接或间接的引用,而这个目录中存在没有定义包名的golang文件,就算golang文件为空,在编译项目时,提示错误信息是:
...expected 'package', found 'EOF'
  1. 每一个可执行项目,必须有一个或多个main包;但在一个main包中,有且只能有一个main函数。如果项目中没有main包,那么在编译项目时,不会出现错误,如果在项目中使用go run来编译并启动项目,则会报错,错误信息是:
go run: cannot run non-main package

导致这个错误的原因是,项目中没有main包,不会生成可执行程序,所以无法启动项目。

虽然项目中可以同时存在多个main包,但是在编译时,只能指定一个main包进行编译。如果一个main包中,有多个main函数,则会无法编译,错误信息是:

main redeclared in this block

如果一个包被定义成main包,那么这个包还能否被其它包引用呢?
答案是:不能

举个例子,在demo3目录中的两个文件内容分别是:

de4.go文件

package main

import (
    "fmt"
)

func Demo3Main4() {
    fmt.Println("demo3 main 4")
}

de5.go文件

package main

import "fmt"

func Demo3Main5() {
    fmt.Println("demo3 main 5")
}

在demo2目录的main函数中引用demo3目录中的main包,示例代码如下:

package main

import (
    demo3 "github.com/hzwy23/GoDemos/demo3"
    "fmt"
)

func main() {
    fmt.Println("hello world")
    demo3.Demo3Main4()
}

在编译时错误信息是:

import "demo3" is a program, not an importable package

错误信息显示demo3目录中是一个程序,而不是一个可导入的包。

小结:

  1. golang使用目录来管理包。简单的说,一个目录,就是一个包。这个目录的子目录,就是这个包的子包。在包被引用时,导入的是包所在目录相对于GOPATH/src目录的相对路径。 如在main函数中引用demo1目录中的demo包
package main

import (
    "fmt"
    "github.com/hzwy23/GoDemos/demo1"
)

func main() {
    fmt.Println("hello world")
    demo.Demo1()
    demo.Demo2()
}

输出结果是:

hello world
hello demo1
hello demo2
  1. 在定义包时,最好将包名设置成目录名,否则会人为的增加麻烦。如包名和目录名不一致,在导入时,需要记住包所在目录,导入后,需要知道目录中包的名字。如果包名和目录名一致,直接根据目录名,就知道包名,使用起来非常方便。

猜你喜欢

转载自blog.csdn.net/hzwy23/article/details/79796850
今日推荐