对同一个 go 文件的 init( ) 调用顺序是从上到下的
对同一个 package 中的不同文件,将文件名按字符串进行“从小到大”排序,之后顺序调用各文件中的init()函数
对于不同的 package,如果不相互依赖的话,按照 main 包中 import 的顺序调用其包中的 init() 函数
如果 package 存在依赖,调用顺序为最后被依赖的最先被初始化,例如:导入顺序 main –> A –> B –> C,则初始化顺序为 C –> B –> A –> main,一次执行对应的 init 方法
![](https://img2018.cnblogs.com/blog/1312420/202002/1312420-20200206202749354-639979104.png)
main函数
//main不支持参数,传参使用os.Args
func main() {
fmt.Println(os.Args)
}
//$: go run main.go 1 2 3
//[/var/folders/4g/nfky9hks3j39qhvz741tmcn40000gn/T/go-build150967295/b001/exe/main 1 2 3]
//main函数不支持返回值
func main() int{
return 10
}
//$: go run main.go
//# command-line-arguments
//./main.go:3:6: func main must have no arguments and no return values
//main函数返回状态值的方法: os.Exit
func main() {
fmt.Println("hello")
os.Exit(-1)
}
//$: go run main.go
//hello
//exit status 255
定义
- 特点
函数是结构化编程的最小模块单元.
将复杂的算法过程分解为若干较小任务, 隐藏相关细节. 使得程序结构更加清晰.便于维护.
普通函数则专注于算法流程,通过接收参数来完成特定逻辑运算,并返回最终结果
支持前置声明
func main() {
test()
}
func test() {
println("100")
}
不支持同名重载
func test() {
println("100")
}
func test() {
println("200")
}
不支持命名嵌套定义
func main() {
func test() {
println("200")
}
}
不支持默认参数
支持不定长边参
func test(a int, n ...int) {
fmt.Println(a, n) //10 [1 2 3]
}
func main() {
arr := []int{1, 2, 3}
test(10, arr...)
}
支持多返回值
支持命名返回值
支持匿名函数和闭包
- 闭包
func test() func() {
age := 0
return func() {
age++
println(age)
}
}
func main() {
f := test()
f()
f()
f()
}
- 延迟调用
func test(fn func()) func() {
time := 0
return func() {
time++
if time > 2 {
fn()
}
}
}
func main() {
run := test(func() {
println("hello world")
})
run()
run()
run() //在执行第三次时才触发
}
只能和nil比较
func(){} == nil
参数
- 参数
不支持可选,不支持命名实参
按顺序传参数
func test(x, y int, s string, _ bool) *int {
return nil
}
func main() {
test(1, 2, "", false)
}
形参类似是局部变量, 重复声明会出错
func test(x, y int) {
x := 100
var y int
}
- 无论是哪种类型都传参都是值传递,无非是拷贝的是指(尽管他们指向的同一个对象)针还是值.
func test(x *int) {
fmt.Printf("%p
", &x)
}
func main() {
a := 10
fmt.Printf("%p
", &a)
test(&a)
}
//0xc0000160c0
//0xc000006030
- 参数过多可以放到一个符合类型中, 变向的实现可选参数和命名实参的功能
type serverOption struct{
address string
port int
path string
timeout time.Duration
log *log.Logger
}
func newOption() *serverOption{
return&serverOption{ // 默认参数
address: "0.0.0.0",
port: 8080,
path: "/var/test",
timeout:time.Second*5,
log: nil,
}
}
func server(option*serverOption) {}
func main() {
opt:=newOption()
opt.port=8085 // 命名参数设置
server(opt)
}
- 可变参数(本质是一个切片,只能放在尾部)
func test(s string,a...int) {
fmt.Printf("%T, %v
",a,a) // 显示类型和值
}
func main() {
test("abc",1,2,3,4)
}
- 切片作为变参时,必须进行展开操作, 如果是数组,则将其转换为切片
func test(a...int) {
fmt.Println(a)
}
func main() {
a:= [3]int{10,20,30}
test(a[:]...) // 转换为slice后展开
}
既然变参是切片,那么参数复制的仅是切片自身,并不包括底层数组,也因此可修改原数据。
返回值
必须要有明确的return语句
- 不明确
func test(x int) int {
if x > 0 {
return 1
} else if x < 0 {
return 0
}
}
- 多返回值用括号括起来
func div(x,y int) (int,error) {
if y==0{
return 0,errors.New("division by zero")
}
- 命名多返回值
func paging(sql string,index int) (count int,pages int,err error) {
}
- 隐式返回
func div(x,y int) (z int,err error) {
if y==0{
err=errors.New("division by zero")
return
}
z=x/y
return // 相当于 "return z,err"
}
- 要命名都命名
匿名函数
没有定义名字符号的函数
可以在函数内部定义匿名函数
可以被直接调用
可保存到变量
可以作为参数和返回值
- 直接执行
func(s string){
println(s)
}("hello mm")
- 存储为变量
s := "hello"
fn := func(s string) {
println(s)
}
fn(s)
- 作为参数
func test(f func()) {
f()
}
func main() {
test(func() {
println("hello,world!")
})
}
- 作为返回值
func test()func(int,int)int{
return func(x,y int)int{
return x+y
}
}
func main() {
add:=test()
println(add(1,2))
}
- 匿名结构体类型
type calc struct{ // 定义结构体类型
mul func(x,y int)int // 函数类型字段
}
- 作为chan元素
x:=calc{
mul:func(x,y int)int{
return x*y
},
}
c:=make(chan func(int,int)int,2)
- 闭包的延迟特性
函数和其引用环境的组合
func test(x int)func() {
return func() {
println(x)
}
}
func main() {
f:=test(123)
f()
}
延迟调用
defer想当前函数注册时候执行的函数调用
因为他直到当前函数执行结束前才执行
常用语资源释放,解除锁定,错误处理等操作
func main() {
f,err:=os.Open("./main.go")
if err!=nil{
log.Fatalln(err)
}
defer f.Close() // 仅注册,直到main退出前才执行
...do something...
}
延迟调用注册的是调用,必须提供执行所需的参数
参数值是在注册时候, 被赋值缓存起来, 如对状态敏感, 可改用指针或闭包
func main() {
x := 1
defer println(x) //注册时拷贝一份当前变量值
x = 100
println(x)
}
// 100 1
多个延迟注册按FILO次序执行。
func main() {
defer println("a")
defer println("b")
}