一、init函数

init初始化函数,会在main函数执行前执行,如果import了其他的包中包含init函数

那么他会优先去扫描导入包中的init函数并执行

案例1 

package main

import "fmt"

func init() {
fmt.Println("test main init")
}


func main(){
fmt.Println("echo main")
}

返回

test main init
echo main

#init函数会在main之前执行

案例2

vi utils/utils.go

package utils

import "fmt"

func init() {
fmt.Println("utils test init")
}
func Test() {
fmt.Println("test")
}

vi main/main.go

package main

import (
"fmt"
"test/utils"

)

func init() {
fmt.Println("main test init")
}
func main(){
utils.Test()
}

返回

utils test init     #先去执行了要导入的包的init
main test init #然后执行了main的init函数,所有init执行完毕后,执行main函数
test #通过main函数调用utils包的test函数,输出test

init函数细节

如果一个文件同时包含"全局变量"、"init函数"、 "main 函数"

#则执行的顺序是
全局变量定义--> init函数--> main 函数

二、 匿名函数

当我们只希望一个函数只需要执行一次时,就可以使用匿名函数,当然匿名函数也可以使用多次

 语法格式

func (形参传入) 返回值列表 {

代码块

}(实参)



#和正常的函数类似,只不过去除了函数的名称
#因为没有函数名,无法调用传参,所以直接在{}后面使用括号()进行参数传递

#例如
func (n1 int,n2 int) int{
return n1 + n2
}(10,20)

案例1   在定义匿名函数时直接使用

package main

import "fmt"

func main() {
//在定义匿名函数时直接使用.这种方式匿名函数只能调用一次
//通过匿名函数,我们指定传入了10、20的值给n1、n2
//通过{} 内返回值是n1+n2的和,返回值类型是int
//通过:= 类型推导 赋值给res1

res1 := func (n1 int,n2 int) int{
return n1 + n2
}(10,20)


fmt.Println(res1) //这样的匿名函数只能使用一次,用作临时运算


}

案例2 将匿名函数写入成一个变量

上面的的方法是给匿名函数直接提供参数进行运算,我们可以把匿名函数定义为一个变量 多次使用

package main

import "fmt"

func main() {


a := func (n1 int,n2 int) int{ //我们将这个匿名函数定义给了a变量 (没有设置参数)
return n1 + n2
}

res2 := a(10,20) //此时a变量就可以看作是一个独立的函数,
//通过a()来调用这个函数,可以多次调用
fmt.Println(res2)


}

案例3 全局匿名函数

package main

import "fmt"

var (
//Fun1 是全局变量,我们将一个匿名函数赋给这个变量,他就可以在整个程序中使用了
//如果首字母大小,那么就可以在不同的包中调用该匿名函数
Fun1 = func (n1 int,n2 int) int {
return n1 * n2
}
)

func main() {

res4 := Fun1(10,20) //调用匿名函数
fmt.Println(res4)
}

三、闭包

案例

package main

import "fmt"

var f = func(int) {} //定义一个匿名函数的变量

func main() {

f = func(i int) { //f可以被任何输入一个整型,并且无返回值的匿名函数给赋值
fmt.Println(i)
}
f(2)

f = func(i int) {
fmt.Println(i * i * i)
}
f(2)
}

匿名函数有动态创建的特性,使得匿名函数不用通过参数传递的方式,就可以直接引用外部的变量。类似常规函数引用全局变量

package main

import "fmt"

func main() {
n := 0 //定义普通变量

f := func() int { //将匿名函数封装为变量
n += 1 //在匿名函数中调用匿名函数外部的变量
//运算会修改外部变量的值
return n
}
fmt.Println(f()) //f()调用匿名函数 去做n += 1的操作
fmt.Println(f()) //通过return n 会将匿名函数计算完的值返回给 n变量
}

 返回

1
2

说明

n := 0
f := func() int {
n += 1
return n
}


//上述代码就是一个闭包,类比于常规函数+全局变量+包。
//f不仅仅是存储了一个函数的返回值,它同时存储了一个闭包的状态。

闭包作为函数返回值

匿名函数作为返回值,不如理解理解为闭包作为函数的返回值,

 案例1 返回值

package main

import "fmt"

func Increase() func() int {
n := 0
ss := func() int {
n++
return n
}
return ss
}

func main() {
in := Increase() //闭包被返回赋予一个同类型的变量时,同时赋值的是整个闭包的状态
//这个状态会一直存在外部被赋值的变量in中
//直到in被消耗,整个闭包也被销毁
fmt.Println(in())
fmt.Println(in())
}

 返回

1
2

案例2 传入参数的返回值

package main
import "fmt"

func AddUpper() func (int) int {
var n int = 10

ss := func (x int) int {
n = n + x
return n
}

return ss
}

func main() {

f := AddUpper()

fmt.Println(f(1))
fmt.Println(f(2))

}

返回

11
13

综合案例

编写一个程序,要求如下
1. 编写一个函数makeSuffix(suffix string) 可以接受一个文件后缀名(比如.jpg),并返回一个闭包
2. 调用闭包,可以传入一个文件名,如果文件没有指定的后缀
(比如.jpg) 则返回文件名.jpg,如果已有.jpg后缀,则返回源文件名

3. 要求使用闭包的方式完成

4. strings.HasSuffix(变量,后缀名) #该函数可以判断字符串是否有指定的后缀

案例

package main

import (
"fmt"
"strings"
)


func makeSuffix(suffix string) func(string) string{

return func(name string) string {
if strings.HasSuffix(name,suffix) == false { //strings.HasSuffix判断name字符串的后缀,是否是.jpg
return name + suffix //如果不是,则结尾添加.jpg
}
return name //如果是,则直接返回该名称
}

}
func main() {
f := makeSuffix(".jpg")

//调用闭包,传入参数到name变量
fmt.Println("文件名处理好=",f("winter"))
fmt.Println("文件名处理好=",f("bird.jpg"))
}