第八章:包

8.1 创建包package

包要求在同一个目录下的所有文件的第一行添加如下代码,以标记该文件归属的包:

package 包名

包的特性如下:

  • 一个目录下的同级文件归属一个包
  • 包名可以与其目录不同名
  • 包名为main的包为应用程序的入口包,编译源码没有main包,将无法编译输出可执行的文件

8.2 导出标识符——让外部访问包的类型和值

8.2.1 导出包内标识符

package mypkg

var myVar = 100

const myCount = "hello"

type myStruct struct {

}

上面的代码中,声明的变量,myVar,myCount,myStruct它们的首字母都为小写,这些变量可以在包内自由使用,但是在包外无法访问它们。
在Go语言中,如果想在一个包里引用另外一个包里的标识符(如类型、变量、常量等)时,必须首先将被引用的标识符导出,将要导出的标识符的首字母大写就可以让引用者可以访问这些标识符了。

package mypkg

var myVar = 100

const MyCount = "hello"

type MyStruct struct {

}

此时,MyCount和MyStruct可以被外部访问。二myVar只能在mypkg包中使用。

8.2.2 导出结构体及接口成员

在被导出的结构体或接口中,如果它们的字段或方法首字母是大写,外部可以访问这些字段和方法,代码如下:

type MyStruct struct {
    // ExportedField 包外可以访问的字段
    ExportedField int
    // privateField 仅限包内访问的字段
    privateField int
}

type MyInterface interface {
    // ExportedMethod 包外可以访问的方法
    ExportedMethod()
    //privateMethod 包内可以访问的方法
    privateMethod()
}

8.3 导入包

要引用其他包的标识符,可以使用import关键字,导入的包名使用双引号包围,包名是从GOPATH开始计算的路径,使用"/"进行路径分隔。

8.3.1 默认导入的写法

  1. 单行导入
import "package_1"
import "package_2"
  1. 多行导入
import (
  "package_1"
  "package_2"
)

示例:
目录层次如下:
src
└── goProjectTest
└── study08
├── main.go
└── mylib
└── add.go

add.go

package mylib

func Add(a, b int) int {
    return a + b
}

main.go

package study08

import (
    "fmt"
    "goProjectTest/study08/mylib"
)

func main()  {
    fmt.Println(mylib.Add(1,2))
}

注意:同一包中不在一个.go文件中无需导入可以直接使用。

8.3.2 导入包后自定义引用包名

在默认的导包的基础上,在导入的包路径前添加标识符即可形成自定义引用包,如下:

customName "path/to/package"
  • path/to/package 要导入的包路径
  • customName 自定义的包名

示例:更改main.go的代码如下:

package study08

import (
    "fmt"
    renameLib "goProjectTest/study08/mylib"
)

func main()  {
    fmt.Println(renameLib.Add(1,2))
}

8.3.3包在程序启动前的初始化入口:ini

Go语言为包提供了一个init()函数,用于调用初始化函数。
init()函数的特性如下:

  • 每个源码可以使用一个init()函数。
  • init()函数会在程序执行前(main()函数执行前)被自动调用。
  • 调用顺序为main()中引用的包,以深度优先顺序初始化。假如:包的引用关系为main->A->B->C,那么这些包的init()函数调用顺序为:C.init->B.init->A.init->main
  • 同一个包中的多个init()函数的调用顺序不可预期。
  • init()函数不能被其他函数调用。

8.3.4 理解包导入后的init()函数初始化顺序

Go会从main包开始检查其引用的所有的包,每个包也可能包含其他的包。Go编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
在运行时,被最后导入的包会最先初始化并调用init()函数。
通过下面的包理解包的初始化顺序

pkginit
├── main.go
├── pkg1
│   └── pkg1.go
└── pkg2
    └── pkg2.go

pkg2.go

package pkg2

import "fmt"

func ExecPkg2()  {
    fmt.Println("ExecPkg2")
}

func init()  {
    fmt.Println("pkg2 init")
}

pkg1.go

package pkg1

import (
    "fmt"
    "goProjectTest/pkginit/pkg2"
)

func ExecPkg1()  {
    fmt.Println("ExecPkg1")
    pkg2.ExecPkg2()
}

func init()  {
    fmt.Println("Pkg1 init")
}

main.go

package main

import "goProjectTest/pkginit/pkg1"

func main()  {
    pkg1.ExecPkg1()
}

代码执行入下:

pkg2 init
Pkg1 init
ExecPkg1
ExecPkg2

你可能感兴趣的:(第八章:包)