1. 包结构概述
Go
GOPATHsrcsrc
.go.go.go.go
GOPATHsrc
wohu@wohu:~/gocode/src$ tree -L 3 
.
├── demo
│   └── demo.go
├── main
│   └── main.go
demo.go
package demo

import "fmt"

func PrintDemo() {
	fmt.Println("This is demo function ")
}

main.go
package main

import "demo"

func main() {
	demo.PrintDemo()
}

源码文件声明的包名可以与其所在目录的名称不同,只要这些文件声明的包名一致就可以。

对引用自定义包需要注意以下几点:

GOPATHGOPATHGOPATHimport包名.函数名demo.PrintDemo()
2. 子目录包名与父目录关系

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

upload
------uploadImage.go
------uploadVideo.go
------uploadText.go
------download   (目录)
------send  (目录)
------receive  (目录)
GOPATH/srcuploaduploadGouploaduploaddownloadsendreceive
downloaddownloaduploadsendsenduploadreceivereceiveupload;

也就是下级目录可以与上级目录声明不同的包名,也可以声明相同的包名。

3.
main

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

workspace
---bin
---pkg
---src
------github.com
---------wohu1104
------------godemos
---------------demo1
------------------de1.go
------------------de2.go
------------------de3_test.go
---------------demo3
------------------de4.go
------------------de5.go
---------------demo2
------------------main.go
------------------demo2.go
------------------demo3.go
demo3de4.gode5.go
demo1de3_test.gode3_test.gode1.gode2.go_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")
}
4. 未定义的包名不能通过编译

如果包被主程序直接或间接的引用,而这个目录中存在没有定义包名的 Golang 文件(就算 Golang 文件为空也不行),在编译项目时,提示错误信息是:

...expected 'package', found 'EOF'
5. 执行没有 main 包的代码会报错

每一个可执行项目,必须有一个或多个 main 包;但在一个 main 包中,有且只能有一个 main 函数。如果项目中没有 main 包,那么在编译项目时,不会出现错误,如果在项目中使用 go run 来编译并启动项目,则会报错,错误信息是:

go run: cannot run non-main package

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

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

main redeclared in this block
6. main 包不能被其它包引用

如果一个包被定义成 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 目录中是一个程序,而不是一个可导入的包。

7. 引用包
GOPATH/src/hzwy23/GoDemos/demo5/logslogsmainlogslogslogs
importGOPATH/src
GOPATH/opt/workspace
bin
pkg
src
---hzwy23
------GoDemos
---------demo5
------------logs
---------------write.go
---------------config.go
---------------logger.go
------------app
---------------main.go
mainlogs

logger.go 文件

package logs
import (
    "fmt"
)
func Info(v ...interface{}) {
    fmt.Println(v...)
}

main.go 文件:

package main
import (
    "github.com/hzwy23/GoDemos/demo5/logs"
)
func main() {
    logs.Info("hello world")
}
importlogsGOPATH/srcInfologslogsGolangpackage
logsGolangloggerloggerloggerInfologger

logger.go 文件:

package logger
import (
    "fmt"
)
func Info(v ...interface{}) {
    fmt.Println(v...)
}

main.go 文件:

package main
import (
    "github.com/hzwy23/GoDemos/demo5/logs"
)
func main() {
    logger.Info("hello world")
}
8. 非 GOPATH 和 GOROOT 包不能被引用
GOPATH/src
GoGOPATH/srcGo SDKGOPATH/srcGo SDK

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