Golang 学习笔记04-函数和指针

Golang 学习笔记04-函数和指针
SEAlencehe定义函数
关键字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)
}
0xc000022070
0xc000022080
可以看到两个变量的内存地址并不一样,函数内部的操作并不会影响到原本的变量
如果要在函数内部修改变量需要传递内存地址
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)
}
0xc000022070
0xc00005c040
张三
指针
&是取地址,*是解引用,去这个地址指向的值
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")
}
init1
init2
init3
main
可以用来初始化全局变量
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)
}
init1
init2
init3
main 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
}
defer3
defer2
defer1
评论
匿名评论隐私政策
✅ 你无需删除空行,直接评论以获取最佳展示效果


