Go 语言-包的引入与用法

目录

1、包介绍

2、标准库

3、程序执行顺序


1、包介绍

包是结构化代码的一种方式:每个程序都由包(通常简称为 pkg)的概念组成,可以使用自身的包或者从其他包中导入内容。

如同其他一些编程语言中的类库或命名空间的概念,每个 go 文件都属于且仅属于一个包。一个包可以有许多以 .go 为扩展名的源文件组成,因此文件名和包名一般来说都是不相同的。

必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main 表示可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

一个应用程序可以包含不同的包,而且即使只使用 main 包也不必把所有的代码都写在一个巨大的文件里:可以用一些较小的文件,并且在每个文件非注释的第一行都使用 package main 来指明这些文件都属于 main 包。如果打算编译包名而不是为 main 的源文件,如 pack1,编译后产生的对象文件将会是 pack1.a 而不是可执行的程序。另外要注意的是,所有的包名都该使用小写字母。

2、标准库

标准库API:Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国

在 Go 的安装文件里包含了一些可以直接使用的包,即标准库。

在 Windows 下,标准库的位置在 Go 根目录下的子目录 pkg\windows_amd64中 ; 在 Linux下,标准库在 Go 根目录下的子目录 pkg\linux_amd64中(如果是安装的是32位,则在(linux_386目录中)。

一般情况下,标准包会存放在$GOROOT/pkg/$GOOS_$GOARCH/目录下。

在这里插入图片描述

Go 的标准库包含了大量的包(如: fmt和os),但是也可以创建自己的包。

如果想要构建一个程序,则包和包内的文件都必须以正确的顺序进行编译。包的依赖关系决定了其构建顺序。属于同一个包的源文件必须全部被一起编译,一个包即是编译时的一个单元,因此根据惯例,每个目录都只包含一个包。

如果对一个包进行更改或重新编译,所有引用了这个包的客户端程序都必须全部重新编译。

Go 中的包模型采用了显式依赖关系的机制来达到快速编译的目的,编译器会从后缀名为 .o的对象文件(需要且只需要这个文件)中提取传递依赖类型的信息。

如果A.go依赖B.go,而B.go又依赖c.go:

①编译c.go,B.go,然后是A.go

②为了编译A.go,编译器读取的是 B.o 而不是c.o

这种机制对于编译大型的项目时可以显著地提升编译速度。

示例:一个程序包含两个包: cat和main,其中 add 包中包含两个变量 Name 和 Age,请问 main 包中如何访问 Name 和 Age?

package main

import (
	"dev_code/day8/demo5/cat"
	"fmt"
)

func main() {
	fmt.Println("猫的名字:", cat.Name)
	fmt.Println("猫的年龄:", cat.Age)
}
package cat

import "fmt"

var Name string = "tom"
var Age int = 5

//初始化函数
func init() {
	fmt.Println("this is cat package")
	fmt.Println("init函数修改前:", Name, Age)
	Name = "jack"
	Age = 3
	fmt.Println("init函数修改后:", Name, Age)
}
//最后运行结果为:

this is cat package
init函数修改前: tom 5
init函数修改后: jack 3
猫的名字: jack
猫的年龄: 3

总结:cat.go 中的全局变量---> cat.go 中的 init() 函数---> main.go 中的 main() 函数。

注意事项:如果导入一个包却没有使用它,则会在构建程序时引发错误,如:imported and not used: os,这正是遵循了”GO 的格言:没有不必要的代码!!!“

3、程序执行顺序

① 按顺序导入所有被 main 包引用的其它包,然后在每个包中执行如下流程:
② 如果该包又导入了其它的包,则从第一步开始递归执行,但是每个包只会被导入一次。
③ 然后以相反的顺序在每个包中初始化常量和变量,如果该包含有init 函数的话,则调用该函数。
④ 在完成这一切之后,main 也执行同样的过程,最后调用 main 函数开始执行程序。

示例:

demo.go文件

package demo

import "fmt"

var Name string
var Age int = 20

func init() {
	fmt.Println("this is demo init()")
	fmt.Println("demo.package.Name=", Name)
	fmt.Println("demo.package.Age=", Age)
	Name = "this is demo init()"
	Age = 200
	fmt.Println("demo.init.Name=", Name)
	fmt.Println("demo.init.Age=", Age)
}

add.go文件

package add

import (
	//对指定包进行初始化,并不做调用处理
	_ "dev_code/day8/demo6/demo"
	"fmt"
)

var Name string = "this is add package"
var Age int = 10

func init() {
	fmt.Println("this is add init()")
	fmt.Println("add.package.Name=", Name)
	fmt.Println("add.package.Age=", Age)
	Name = "this is add init()"
	Age = 100
	fmt.Println("add.package.Name", Name)
	fmt.Println("add.package.Age", Age)
}

main.go文件

package main

import (
	a "dev_code/day8/demo6/add"
	"fmt"
)

func main() {
	//main包---->add包----->demo包
	fmt.Println("Name=", a.Name)
	fmt.Println("Age=", a.Age)
}

运行结果为:

this is demo init()
demo.package.Name= 
demo.package.Age= 20
demo.init.Name= this is demo init()
demo.init.Age= 200
this is add init()
add.package.Name= this is add package
add.package.Age= 10
add.package.Name this is add init()
add.package.Age 100
Name= this is add init()
Age= 100

总结:

包引用的时候顺序:main引用add包,add再引用demo包;

编译执行流程:先从demo包这里编译加载里面的全局变量,然后执行init函数,当init函数执行完成以后再去执行add中的全局变量,再执行里面的init函数,最后执行main包中的函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值