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]int{1,2,3}
不限长数组 [...]int{1,2,3}
查和改没问题 a:=arr[1] arr[1]=5
访问:直接查询,遍历循环
var arr=[3]int{1,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]int{1,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]int{1,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=[]int{1,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=[]int{1,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 = []int{1, 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
标签:闭包,defer,函数,int,fmt,var,func,Println,main 来源: https://www.cnblogs.com/ztgolang/p/15902711.html