菜鸟笔记
提升您的技术认知

Go语言包 package

什么是package

package起到组织源代码的作用,并实现了命名空间的管理。在Go语言中,每一个源文件都属于package的一部分,在文件头部用package声明所属包的名称:

package main

import (
    "fmt"
)


func main() {
    fmt.Println("Hello World!")
}

作用

包由一个或多个保存在同一目录下(不含子目录)的源码文件组成。包的用途类似命名空间,是成员作用域和访问权限的边界。

命名规则

  • 包名与目录名无关,不要求保持一致
  • 包名通常使用单数形式。源文件必须使用UTF-8格式,否则会导致编译出错

特殊含义的包

包名 描述
main 可执行入口(入口函数mian.main)
all 标准库以及GOPATH中能找到的所有包
std 标准库及工具链
cmd 标准库及工具链
documentation 存储文档信息,无法导入(和目录名无关)

权限

所有成员在包内均可访问,无论是否在同一份源码文件中。但只有名称首字母大写的为可导出成员,在包外可视(该规则适用于全局变量、全局常量、类型、结构字段、函数和方法)。不过通过指针转换的方式可以绕开该权限限制:

例如如下的包结构中:


├── main.go
├── school
    └── student.go

school/student.go中定义了一个不能在包外可视的类型student,它有两个成员属性,Name和Age,都是可以包外可视的。该源码文件中同时还定义了一个函数NewStudent,返回一个指向student的指针:

package school

type student struct {
	Name string
	Age  int
}

func NewStudent(name string, age int) *student {
	return &student{
		Name: name,
		Age: age,
	}
}

在main.go中,虽然不能对student结构可视,但是通过调用NewStudent函数,我们可以绕开该限制:

package main

import (
	"fmt"
	"go-exercise/school"
)

func main() {
	stu := school.NewStudent("Bob", 13)
	fmt.Printf("%T, %s, %d\n", stu, stu.Name, stu.Age)
	// output: *school.student, Bob, 13
}

初始化

init函数用于package的初始化操作。每一个package内可以定义多个init函数,这些函数可以分布在package中的每一个源码文件中。但编译器不保证这些init函数的执行次序。

package main

import (
	"fmt"
)

func init() {
	fmt.Println("in init function...")
}

func main() {
	fmt.Println("in main function...")
	// outputs:
	// in init function...
	// in main function...
}