定义函数
关键字func
func sayHello(id int) { fmt.Println("hello world", id)}多个参数类型一致可以省略
func sayHello(id, age int) { fmt.Println("hello world", id)}func add(numberList ...int) { var sum int for _, number := range numberList { sum += number } fmt.Println(sum)}numberList: 可变参数,类型为 []int(整数切片)range: Go 语言的关键字,用于遍历数组、切片、映射等数据结构_: 空白标识符,用于忽略索引值(range 返回索引和值两个值)number: 接收遍历到的每个元素值的变量名
函数返回值
和TS类似,括号外面写返回值类型
func add2() int { var sum int for i := 1; i <= 100; i++ { sum += i } return sum}
func main() { var res = add2() fmt.Println(res)}返回多个值
返回值类型用括号括起来
func add3() (int, int) { var sum int for i := 1; i <= 100; i++ { sum += i } return sum, 100}func main() { var res2, res3 = add3() fmt.Println(res2, res3)}命名返回值
相当于先定义再赋值,返回值的类型前加上变量名
func add4() (sum int, age int) { for i := 1; i <= 100; i++ { sum += i } age = 18 return}func main() { var res4, res5 = add4() fmt.Println(res4, res5)}5050 18匿名函数
Go不能在函数体中定义函数,但是可以把函数赋值给变量,和js的箭头函数有点像
func main() { var getName = func() string { return "张三" } var name = getName() fmt.Println(name)}高阶函数
把一个函数作为参数传到另一个函数里面,或者把函数作为参数传到其他的数据类型里面去
例子:
根据用户的不同输入采取不同的操作
传统写法
func get() { fmt.Println("查询用户信息")}
func addUser() { fmt.Println("添加用户信息")}
func del() { fmt.Println("删除用户信息")}
func main() { var id int fmt.Scan(&id) switch id { case 1: get() case 2: addUser() case 3: del() default: fmt.Println("输入错误") }}定义一个map,输入的id就是key,对应的value就是函数
var id int fmt.Scan(&id)
var funMap = map[int]func(){ 1: get, 2: addUser, 3: del, } fun, ok := funMap[id] if ok { fun() }闭包
设计一个函数,先传一个参数表示延时,后面再次传参数就是将参数求和
例如
fun(2)(1,2,3) // 延时2秒求1+2+3写法一
package main
import ( "fmt" "time")
func awaitAdd(awaitSecond int) func(...int) int { time.Sleep(time.Duration(awaitSecond) * time.Second) // 返回的是一个函数 return func(nunberList ...int) int { var sum int for _, number := range nunberList { sum += number } return sum }}
func main() { // 这里的timeRes是一个函数类型 timeRes := awaitAdd(2) t1 := time.Now() sumRes := timeRes(1, 2, 3) sunTime := time.Since(t1) fmt.Println(sumRes, sunTime) //6 0s}写法二
func awaitAdd(awaitSecond int) func(...int) int { //time.Sleep(time.Duration(awaitSecond) * time.Second) // 返回的是一个函数 return func(nunberList ...int) int { time.Sleep(time.Duration(awaitSecond) * time.Second) var sum int for _, number := range nunberList { sum += number } return sum }}func main() { // 这里的timeRes是一个函数类型 timeRes := awaitAdd(2) t1 := time.Now() sumRes := timeRes(1, 2, 3) sunTime := time.Since(t1) fmt.Println(sumRes, sunTime) //6 0s}这时候内层函数捕获外层变量: 闭包捕获了外层函数的参数 awaitSecond
- 内层匿名函数“记住”了外层的 awaitSecond 变量
- 即使外层函数执行完毕,awaitSecond 的值仍被保留在闭包中
可以函数嵌套函数
值传递和引用传递
func copyName(name string) { fmt.Printf("%p\n", &name)}func main() { name1 := "张三" fmt.Printf("%p\n", &name1) copyName(name1)}0xc0000220700xc000022080可以看到两个变量的内存地址并不一样,函数内部的操作并不会影响到原本的变量
如果要在函数内部修改变量需要传递内存地址
func SetName(name *string) { fmt.Printf("%p\n", &name) // 通过内存地址去找这个值 *name = "张三"}func main() { name1 := "李四" fmt.Printf("%p\n", &name1) //copyName(name1) SetName(&name1) fmt.Println(name1)}0xc0000220700xc00005c040张三指针
&是取地址,*是解引用,去这个地址指向的值
init函数
init()函数是一个特殊的函数,存在以下特性:
- 不能被其他函数调用,而是在main函数执行之前,自动被调用
- init函数不能作为参数传入
- 不能有传入参数和返回值
一个go文件可以有多个init函数,谁在前面谁就先执行
package main
import "fmt"
func init() { fmt.Println("init1")}func init() { fmt.Println("init2")}func init() { fmt.Println("init3")}func main() { fmt.Println("main")}init1init2init3main可以用来初始化全局变量
package main
import "fmt"
var db int
func init() { db = 1 fmt.Println("init1")}func init() { fmt.Println("init2")}func init() { fmt.Println("init3")}func main() { fmt.Println("main", db)}init1init2init3main 1初始化顺序
defer函数
- 关键字 defer 用于注册延迟调用
- 这些调用直到 return 前才被执。因此,可以用来做资源清理
- 多个defer语句,按先进后出的方式执行,谁离return近谁先执行
- defer语句中的变量,在defer声明时就决定了,即声明defer之前的变量
package main
import "fmt"
func main() { defer fmt.Println("defer1") defer fmt.Println("defer2") defer fmt.Println("defer3") return}defer3defer2defer1


