Day04 Go语言函数:值传递匿名函数高阶函数闭包和defer语句
Posted 澐湮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day04 Go语言函数:值传递匿名函数高阶函数闭包和defer语句相关的知识,希望对你有一定的参考价值。
01 上节回顾
数据类型:
整型和浮点型 布尔型 字符串
默认值:
nil 空对象
数字 var arr [3]int
默认值
package main import "fmt" func main() //零值 var s string var x int var arr [3]int //数组是值类型 var b bool fmt.Println(s) fmt.Println(x) fmt.Println(arr) //[0 0 0 ] fmt.Println(b) //false
数组回顾:
[3]int 和[4]int是俩类型
声明并赋值 var arr=[3]int1,2,3
不限长数组 [...]int1,2,3
查和改没问题 a:=arr[1] arr[1]=5
访问:直接查询,遍历循环
var arr=[3]int1,2,3 for i,v:=range arr fmt.Println(i,v)
切片回顾:
起始位置地址,长度,容量
1、定义s1,从数组上切
2 再扩容s1,100换成500
3 对s4扩容
4 重新赋给s1,s1的地址没变,只是把3改为4
案例 切片本质
package main import ( "fmt" ) func main() /* //切片本质1 var s = [5]int1,2,3,4,5 s1:=s[0:3] s2:=s[2:4] fmt.Println("s1:",s1,len(s1),cap(s1)) fmt.Println("s2:",s2,len(s2),cap(s2)) s3:=append(s1,100) fmt.Println(s3,len(s3),cap(s3)) s4:=append(s3,500) fmt.Println(s4,len(s4),cap(s4)) s5:=append(s4,1000) fmt.Println(s5,len(s5),cap(s5))*/ //切片本质2 var s = [5]int1,2,3,4,5 s1:=s[0:3] fmt.Printf("%p\\n",s1) //0xc00000c330 s1=append(s1,100) fmt.Printf("%p\\n",s1) //0xc00000c330
02 回顾 map
hash结构
数组根据索引查找
map根据键查找
map声明 赋值
package main import "fmt" func main() //切片 var s1 = make([]int,3) fmt.Println(s1) // [0 0 0] //map1 var m1 map[string]string m1=make(map[string]string) m1["name"]="yuan" m1["age"]="22" fmt.Println(m1) //map[age:22 name:yuan]
interface类型
定义map的值为interface类型
package main import "fmt" func main() //示例1 map interface类型 m2:=make(map[string]interface) m2["name"]="yuan" m2["age"]=22 m2["ISMarried"]=false fmt.Println(m2) //map[ISMarried:false age:22 name:yuan] // 示例2 map interface类型 m3:=map[string]interface"name":"yuan","age":22 fmt.Println(m3) //map[age:22 name:yuan]
map查询
取1002学生第二科目成绩
package main import "fmt" func main() //取1002学生第2科目成绩 var m4 = map[string][]int"1001":100,90,80,"1002":89,90,91 fmt.Println(m4["1002"][1]) //90
map遍历
package main import "fmt" func main() //取1002学生第2科目成绩 var m4 = map[string][]int"1001":100,90,80,"1002":89,90,91 fmt.Println(m4["1002"][1]) //90 for k,v:=range m4 fmt.Println(k,v) fmt.Println("m4长度:",len(m4)) //m4长度: 2
遍历map对应的切片元素
package main import "fmt" func main() //取 var m4 = map[string][]int"1001":100,90,80,"1002":89,90,91 for k,v:=range m4 fmt.Println(k,v) for i,v2:=range v fmt.Printf("i:%d v2:%d\\n",i,v2)
打印结果
1001 [100 90 80]
i:0 v2:100
i:1 v2:90
i:2 v2:80
1002 [89 90 91]
i:0 v2:89
i:1 v2:90
i:2 v2:91
03 回顾 函数
函数声明和调用
什么是函数? 代码的组织形式
函数声明和调用
参数
参数是个赋值的过程,值拷贝
参数什么意思?为了能够在函数调用的时候动态传入一些值给函数
func xunhuan(m map[string][]int) for k,v:=range m fmt.Println(k,v) for i,v2:=range v fmt.Printf("i:%d,v2:%d",i,v2)
位置参数
必备参数,传入实际参数,参数位置和数量必须与定义的一致
可变参数
可变参数(不定长参数)通常放在函数最后
package main import "fmt" func sum(base int,nums ...int)int fmt.Println(base,nums) sum:=base for _,v:=range nums sum+=v return sum func main() ret:=sum(10,2,3,4) fmt.Println(ret) 打印结果 10 [2 3 4] 19
返回值
没有返回值,不能赋值给一个新的变量
案例 返回值
package main import "fmt" func xunhuan(m map[string][]int) int var ret = 0 for _,scores :=range m //fmt.Println(sid,scores) var s=0 for _,v2:=range scores s+=v2 average :=s/3 //fmt.Println(sid,"的average",average) ret+=average mAverage:=ret/len(m) //fmt.Println("mAverage",mAverage) return mAverage func main() var m3=map[string][]int"1001":100,90,80,"1002":91,90,89 fmt.Println("1002:::",m3["1002"][1]) var m4=map[string][]int"1003":100,90,80,"1004":91,90,89 //函数 var r1 = xunhuan(m3) fmt.Println("r1",r1) var r2 = xunhuan(m4) //m4是实际参数 fmt.Println("r2",r2)
返回值命名
func calc(x,y int) (sum,sub int) sum = x+y sub = x-y return //return sum sub func main() //返回值 var a,c = calc(2,1) fmt.Println(a,c)
重新赋值
func calc(x,y int) (sum,sub int) sum = x+y sub = x-y //return //return sum sub return 5,6
04 指针类型
package main import ( "fmt" "reflect" ) func main() //声明赋值一个整型变量 var x int x = 100 //存整型数字的变量称为整型变量 var p *int //存地址的变量称为指针变量 *类型 p = &x fmt.Println(p, reflect.TypeOf(p))
案例
package main import ( "fmt" "reflect" ) func main() /* var x=10 fmt.Println(&x) //0xc00000a0b8 x=100 fmt.Println(&x) //0xc00000a0b8 var s = "hello" fmt.Println(s)*/ //声明赋值一个整型变量 //var x int = 100 var x int x = 100 /* var p=&x fmt.Println(p,reflect.TypeOf(p)) //0xc00000a0b8 *int*/ var p *int // fmt.Println(p,*p) //思考*p等于什么? panic: runtime error: invalid memory address or nil pointer dereference p=&x fmt.Println(p,reflect.TypeOf(p)) //0xc00000a0b8 *int
05 值传递
案例1
x和y地址一样不一样?
package main import "fmt" func main() //案例1 var x=10 fmt.Printf("x的地址%p\\n",&x) //x的地址0xc00000a0b8 y:=x fmt.Printf("y的地址%p\\n",&y) //y的地址0xc00000a0f0 x=100 fmt.Println(y) //10
案例2 切片拷贝
package main import "fmt" func main() //案例2 var a=[]int1,2,3 b:=a a[0]=100 fmt.Println(b) //[100 2 3]
案例1 函数传参-传值
package main import "fmt" func func01(a int) //fmt.Println(x) a=100 func main() //函数传参 //案例1 var x=10 func01(x) //本质是a=x 把10赋给a fmt.Println(x) //10
案例2 函数传参-传地址
希望打印修改后的值
一切为值拷贝
把p的值(x的地址),拷贝一份
package main import "fmt" func func02(a *int) fmt.Println(a) //x的地址 fmt.Println(*a) func main() //函数传参 //案例2 var x=10 var p *int=&x fmt.Println(p) func02(p) //a=p fmt.Println(":::",x)
打印结果
0xc00000a0b8
0xc00000a0b8
10
::: 10
本质:通过切片和传地址实现引用的修改效果
b=*a 是把地址对应的值取出来,b=*a 赋给了变量
练习 函数传参
package main import "fmt" func func02(s []int) fmt.Printf("func02的s的地址:%p\\n",&s) s[0]=100 func func03(p *int) *p=100 func main() //案例2 var s=[]int1,2,3 fmt.Printf("main的s的地址:%p\\n",&s) //main和func02中s地址不一样√ func02(s) fmt.Println(s) //案例3 var a=10 var p *int =&a func03(p) fmt.Println(a)
06 下午 函数传参的案例
传参的过程,就是拷贝的过程,再传参
不同点在于: 指针传的是地址,切片指的是底层数组
案例2传地址回顾
取址和赋值
package main import ( "fmt" "reflect" ) func func02(a *int) fmt.Println(a) //x的地址 fmt.Println(*a,reflect.TypeOf(*a)) //10 int
*a = 100 func main() //案例 var x=10 var p *int=&x fmt.Println(p) func02(p) //a=p fmt.Println(":::",x)
案例3传切片
package main import ( "fmt" "reflect" ) func func03(s []int) fmt.Printf("func02的s的地址:%p\\n",&s) s[0] = 100 // s = append(s, 1000) func main() //案例3 var s = []int1, 2, 3 fmt.Printf("main的s的地址:%p\\n",&s) func03(s) fmt.Println(s) 打印结果 main的s的地址:0xc000096060 func02的s的地址:0xc000096078 [100 2 3]
案例3图解
声明调用
参数
返回值
作用域
传参
07下午 匿名函数
函数里边只能生成匿名函数
匿名函数的使用
方式1
package main import "fmt" func main() //匿名函数的使用 var foo= func () fmt.Println("hello yuan") foo() //hello yuan
方式2:只用1次,就不用命名了
本质:是把函数整体赋值给bar变量了
package main import "fmt" func main() //方式2 func() fmt.Println("hello yuan") () //hello yuan //匿名函数传参 (func(x,y int) fmt.Println(x+y) )(4,5) //9
匿名函数的形参和实参
package main import "fmt" func main() //匿名函数 var foo= func () fmt.Println("hello yuan") foo() //hello yuan //方式2 func() fmt.Println("hello yuan") () //hello yuan (func(x,y int) fmt.Println(x+y) )(4,5) //9
练习
package main import "fmt" func main() //匿名函数 var foo= func () fmt.Println("hello yuan") foo() //方式2 func() fmt.Println("hello yuan") () (func(x,y int) fmt.Println(x+y) )(4,5)
08高阶函数
package main import "fmt" func bar() fmt.Println("bar") func main() var foo = bar foo()
设计一个函数,打印出来执行的时间
时间操作
package main import ( "fmt" "time" ) func main() //引入时间操作 fmt.Println(time.Now().Unix()) time.Sleep(time.Second*2) fmt.Println(time.Now().Unix())
函数类型
函数类型有区别,函数的类型会根据参数和返回值变化
package main import ( "fmt" "reflect" ) func bar1() fmt.Println("hello") func bar2(x,y int) fmt.Println(x+y) func bar3(x,y int) int return x+y func main() fmt.Println(bar1,reflect.TypeOf(bar1)) //0xc3c560 func() fmt.Println(bar2,reflect.TypeOf(bar2)) //0x3bc5e0 func(int, int) fmt.Println(bar3,reflect.TypeOf(bar3)) //0xbdc660 func(int, int) int
以函数作为参数
课堂练习
package main import ( "fmt" "time" ) func bar() time.Sleep(time.Second*3) fmt.Println("bar") func foo() time.Sleep(time.Second*2) fmt.Println("foo") func funcTimer(f func()) t1:=time.Now().Unix() f() t2:=time.Now().Unix() fmt.Println("spend time:",t2-t1) func main() /* //引入时间操作 fmt.Println(time.Now().Unix()) time.Sleep(time.Second*2) fmt.Println(time.Now().Unix()) fmt.Println(foo,reflect.TypeOf(foo))*/ funcTimer(foo) funcTimer(bar)
09 双值计算器-函数作为参数
package main import "fmt" //双值运算器 func add(x,y int)int return x+y func mul(x,y int)int return x*y func cal(a,b int,calFunc func(int,int) int) ret:=calFunc(a,b) fmt.Println(ret) func main() cal(10,5,mul)
10高阶函数2
以函数作为返回值
package main import ( "fmt" ) func foo() func(int,int) string /*var bar = func(x,y int) string fmt.Println("bar...") return "bar" return bar*/ return func(x,y int)string fmt.Println("bar...") return "bar" func main() var ret = foo() ret(1,2)
函数作为返回值,里边俩函数问题?看return的函数,a会飘红
import "fmt" func foo() func(int,int) string var bar = func(x,y int) string fmt.Println("bar...") return "bar" var a=func(x,y int) string return "a" return bar
11闭包
闭包是引用了自由变量的函数。 自由变量:外部非全局变量
闭包是: 函数+所依赖的环境
package main import ( "fmt" ) func foo() func() var x=100 var bar = func() fmt.Println("bar",x) return bar func main() var f = foo() //闭包函数 f()
ret只接收了返回值,拷贝了return的结果
package main import ( "fmt" ) func a() int i:=100 fmt.Println(i) return 100 func main() var ret = a() fmt.Println(ret)
闭包会对内存造成一定的压力
12 闭包应用-装饰函数
记录被调用次数的功能
package main import "fmt" //装饰函数: 记录某个函数的调用次数 var callerCount = 0 func counter(f func()) f() callerCount++ func foo() fmt.Println("foo function调用") func main() counter(foo) counter(foo) counter(foo) counter(foo) counter(foo) fmt.Println(callerCount)
修改
package main import "fmt" //装饰函数: 记录某个函数的调用次数 func counter(f func()) func() var callerCount = 0 return func() f() callerCount++ fmt.Println("调用次数:",callerCount) //测试的调用函数 func foo() fmt.Println("foo function调用") func main() newFoo:=counter(foo) newFoo() newFoo()
调用bar函数
package main import "fmt" //装饰函数: 记录某个函数的调用次数 func counter(f func()) func() var callerCount = 0 return func() f() callerCount++ fmt.Println("调用次数:",callerCount) //测试的调用函数 func foo() fmt.Println("foo function调用") func bar() fmt.Println("bar function调用") func main() newFoo:=counter(foo) newBar:=counter(bar) newFoo() newFoo() newBar()
开放封闭性
package main import "fmt" //装饰函数: 记录某个函数的调用次数 func counter(f func()) func() var callerCount = 0 return func() f() callerCount++ fmt.Println("调用次数:",callerCount) //测试的调用函数 func foo() fmt.Println("foo function调用") func main() foo:=counter(foo) foo()
闭包练习题
package main import "fmt" func foo() fmt.Println("foo function调用") func main() fmt.Println("test01") defer foo() //延迟调用 fmt.Println("test02")
打印结果
test01
test02
foo function调用
13 defer语句
defer 应用场景
package main import ( "fmt" "os" ) func main() //打开文件 fileObj,err:=os.Open("满江红") defer fileObj.Close() if err!=nil fmt.Println("文件打开失败,错误原因",err) fmt.Println(fileObj)
多个defer应用
package main import ( "fmt" ) func foo() fmt.Println("foo function调用") func bar() fmt.Println("bar function调用") func main() fmt.Println("test01") defer foo() //先注册的后调用 fmt.Println("test02") defer bar() //延迟调用
defer的拷贝机制
案例1
函数注册的是谁,连参数一块儿保存下来
package main import "fmt" func main() //(3) defer的拷贝机制 foo := func() fmt.Println("I am function foo1") defer foo() foo = func() fmt.Println("I am function foo2")
案例2
package main import "fmt" func main() // 案例2 x:=10 defer func(a int) fmt.Println(a) (x) x++
案例3
package main import "fmt" func main()
// 案例3 x:=10 defer func() fmt.Println(x) () x++ //x=x+1
defer执行时机
//defer执行时机
//return 10
//(1) rval = 10
//defer执行
//(2) ret
闭包进阶-练习题
版本1
package main import "fmt" func main() //版本1 var fn [10]func() for i:=0;i<len(fn);i++ // 没发生调用,第1次执行 fn[0]=func()fmt.Println(i) // 没发生调用,第2次执行 fn[1]=func()fmt.Println(i) // 没发生调用,第3次执行 fn[2]=func()fmt.Println(i) fn[i]=func() fmt.Println(i) //for循环执行完,内存中有一块地址存储 func()fmt.Println(i) i=10 for _,f:=range fn f() 打印结果 10个 10
版本2 把range循环换成三要素循环
package main import "fmt" func main() //版本2 var fn [10]func() for i:=0;i<len(fn);i++ fn[i]=func() fmt.Println(i) //for循环执行完,内存中func()fmt.Println(i) i=10 //注意i=10是上边for循环中的局部i for i:=0;i<len(fn);i++ //每次都调用(局部i=10) func()fmt.Println(i) i=10 fn[i]() 打印结果 10个 10
版本3 把i换成j
package main import "fmt" func main() //版本3 var fn [10]func() for i:=0;i<len(fn);i++ fn[i]=func() fmt.Println(i) //for循环执行完,内存中func()fmt.Println(i) i=10 //注意i=10是上边for循环中的局部i for j:=0;j<len(fn);j++ //每次都调用(局部i=10) func()fmt.Println(i) i=10 fn[j]() 打印结果 10个 10
版本4
//版本4 var fn [10]func() var i int for i=0;i<len(fn);i++ fn[i]=func() fmt.Println(i) fmt.Println("----",i) //for循环执行完,内存中func()fmt.Println(i) i=10 //这里i=10是var i int声明的i 下边for循环中的i 也是同一个i for i=0;i<len(fn);i++ //for i=0;i<5;i++ //更换为 i<5 打印 0 1 2 3 4 fn[i]() fmt.Println("====",i)
版本4 理解 代码段
var i int for i=0;i<10;i++ fmt.Println("for",i) fmt.Println("main",i) for i=0;i<5;i++ fmt.Println("for",i) fmt.Println("main2",i) 打印结果 for 0 for 1 for 2 for 3 for 4 for 5 for 6 for 7 for 8 for 9 main 10 for 0 for 1 for 2 for 3 for 4 main2 5
版本4 帮助理解的代码段2
//版本4 var fn [10]func() var i int for i=0;i<len(fn);i++ fn[i]=func() fmt.Println(i) fmt.Println("----",i) for i=0;i<5;i++ fn[i]() fmt.Println("====",i) 打印结果 ---- 10 0 1 2 3 4 ==== 5
版本5
package main import "fmt" func makeFun(i int)func() return func() fmt.Println(i) func main() //版本5 var fn [10]func() for i:=0;i<len(fn);i++ fn[i]=makeFun(i) for _,f:=range fn f()
版本6
package main import "fmt" func makeFun2()func(i int) return func(i int) fmt.Println(i) func main() //版本6 var fn [10]func(int) for i:=0;i<len(fn);i++ fn[i]=makeFun2() for i,f:=range fn f(i) 打印结果 0 1 2 3 4 5 6 7 8 9
以上是关于Day04 Go语言函数:值传递匿名函数高阶函数闭包和defer语句的主要内容,如果未能解决你的问题,请参考以下文章