函数是什么?
学过编程的 xdm 对于函数自然不会陌生,那么函数是什么呢?
函数是一段可以重用的代码块,可以被多次调用,我们可以通过使用函数,提高咱们代码代码的模块化,提高程序的可读性和可维护性
对 GO 语言中的函数,入参可以有多个,返回值也可以有多个,此处建议,入参不大于 5 个,如果超过 5 个最好使用传入结构的方式来进行处理
程序的初始化顺序?
要了解 GO 语言中程序的初始化顺序,就要先明白整个程序初始化流程中,都会涉及到哪一些内容
GO 语言中以包 package 作为 程序逻辑封装的基本单元,每一个包我们可以理解为他是独立的,封装良好的,并且对外暴露了接口的基本单元
然而,咱们的 GO 程序就是由这些包组成的,那么这个包里面一般又包含着 基本的常量,变量,函数,类型,方法,和接口等等
那么对于上述这些元素,我们就要弄明白在包里面他们是如何有序的进行初始化的
本章主要分享函数,GO 语言中除了 main 函数,还有一个特殊的函数就是 init 函数
kotlin复制代码fun init() {
// 具体的实现
// 具体的初始化
}
这里可以看到init 函数,是没有入参,也没有返回值的函数
init 函数用于在本包中进行初始化和做一些程序初始状态的检查工作,例如我们会把一些单例,数据库句柄,各种连接句柄放到 init 函数中进行初始化,init 函数在整个程序生命周期,只会被调用一次
且这里我们需要注意,一个包里面会有多个 GO 语言源文件,这些源文件中都可以定义 init 函数,但是在程序执行 init 函数时,是一个一个的去执行的,而不是并发的去执行的,那么此处的执行顺序我们就不要去过度依赖,按照我们使用惯例来看,过度依赖 init 函数的执行顺序可能会出现意想不到的问题
所以此处我们就需要注意,如果不同的 init 函数实现中,相互有依赖,那么可能就会导致程序出现我们不期望的结果
那么整个程序的初始化流程和顺序我们要知道是这样子的:
对于一个包而言,初始化顺序如下:
包内的包级常量
包内的包级变量
包内的 init 函数
对于一个程序里面,从 main 函数开始,必然是包含了其他的子包,那么初始化的时候是怎么样的呢?
先是初始化子包,若子包里面还有子包,那么就继续从最深一层的子包开始按照包里面的初始化顺序进行
最深一层的子包按照顺序初始化完毕之后,就到了他的父级包开始按照顺序初始化
走到 main 包中的 包级常量,包级变量, init 函数进行初始化
最终,执行 main 函数
通过上图是不是对于 GO 程序初始化顺序更加清晰了呢,如果有表述不当的地方,还请多多评论留言,多多指教
我们可以写一个 demo 来看看效果:
demo 的目录结构如下
main.go 文件的内容如下:
package main
import "fmt"
import _ "ttt/p1"
import _ "ttt/p2"
var (
_ = checkConst()
c = varInit(4)
d = varInit(5)
)
const (
a = 2
b = 3
)
func init() {
fmt.Println("main : init")
}
func checkConst() int {
if a == 2 {
fmt.Println("main : const a")
}
if b == 3 {
fmt.Println("main : const b")
}
return 0
}
func varInit(x int) int {
fmt.Println("main : var ", x)
return x
}
func main() {
fmt.Println("main : main ")
}
main 包中,我们导入了 p1 和 p2 包,main 包中定义了 const 常量和变量,以及 对应的 init 函数
p1 和 p2 包的内容和 main 的大体一直
运行程序之后,我们可以看到打印的结果如下, 通过这个 demo 我们就可以看到程序的初始化顺序正如上所述
p1 : const a
p1 : const b
p1 : var 4
p1 : var 5
p1 : init
p2 : const a
p2 : const b
p2 : var 4
p2 : var 5
p2 : init
main : const a
main : const b
main : var 4
main : var 5
main : init
main : main
具体的 demo 仓库可以查看如下地址:
GO 语言程序初始化顺序 demo
函数在 GO 语言中的地位?
在 GO 中,我们可以看到没有那些高级语言面向对象的语法,例如 Class 类,继承,对象等等内容, GO 语言中可以通过函数或者方法的方式进行各种组合完成我们想做的一切事项
此处就体现了函数在 GO 语言中是极其的重要,函数在 GO 语言中是 一等公民 的存在。
如何体现 一等公民呢?函数在 GO 中可以像普通类型的值一样被创建和被使用,使用起来非常灵活和自由
例如,创建的函数可以存储在变量中,也可以做为其他函数的返回值(在函数内部创建了函数变量之后,通过返回值返回),还可以作为其他函数的参数进行传递
那么我们就来写一些 demo 查看这个 一等公民 是有多么的自由吧:
1.正常写一个 函数,简单实现
func helloworld() string{
name := "阿兵云原生"
return name
}
2.函数作为入参
go复制代码func add(a, b int) int {
return a + b
}
func cal(a int, f func(int, int) int) int {
return a + f(a, a)
}
函数作为返回值返回出去
func add(a, b int) int {
return a + b
}
func getFunc() func(int, int) int{
return add
}
将函数存储在变量中使用
type TestFunc struct {
f func(int, int) int
name string
}
func add(a, b int) int {
return a + b
}
func main() {
tt := &TestFunc{f: add, name: "阿兵云原生"}
fmt.Println(tt.f(1,2))
}
函数作为类型来使用