欢迎来我的个人博客:fizzyi
自定义函数
1.定义格式
函数构成代码执行的逻辑结构。在Go语言中,函数的基本组成为:关键字func,函数名,参数列表,返回值,函数体和返回语句。
Go语言函数定义格式如下:
func FuncName(/*参数列表*/)(o1 type1,o2 type2/*返回类型*/)
//函数体
return v1,v2//返回多个值
返回类型说明:
上面返回值声明了两个变量名o1和o2(命名返回参数),这个不是必须,可以只有类型没有变量名
如果只有一个返回值且不声明返回值变量,那么你可以省略,包括返回值的括号
如果没有返回值,那么就直接省略最后的返回信息。
如果有返回值,那么必须在函数的内部添加return语句
2.函数定义
2.1无参数无返回值
func Test(){ //无参数无返回值函数定义
fmt.Println('this is a test func')
}
func main(){
Test() //无参数无返回值函数调用
}
2.2有参数无返回值
2.2.1普通参数列表
func Test01(v1 int ,v2 int){ //方式一
fmt.Printf("v1 = %d,v2 = %d\n",v1,v2)
}
func Test02(v1,v2 int){ //方式2,v1,v2都是Int类型
fmt.Printf("v1 = %d ,v2 =%d\n",v1,v2)
}
func main(){
Test01(10,20)
Test02(11,22)
}
2.2.2不定参数列表
不定参数是指函数传入的参数个数为不定数量,为了做到这点,首先需要将函数定义为接受不定参数类型
//形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数
func Test(args ...int){
for _,n := range args{ //遍历参数列表
fmt.Println(n)
}
}
func main(){
//函数调用,可传0到多个参数
Test()
Test(1,2,3,4)
}
2.3无参数有返回值
有返回值的函数,必须有明确的终止语句,否则会引发编译错误
2.3.1一个返回值
func Test01() int { //方式1
return 250
}
func Test02()(value int ){ //方式2,给返回值命名
value =250
return value
}
2.3.2多个返回值
func Test01()(int ,string){ //方式1
return 250,"sb"
}
func Test02()(a int ,str string){ //方式2,给返回值命名
a = 250
str = "sb"
return
}
2.3.3有参数有返回值
\#求两个数的最小值和最大值
func MinAndMax(num1 int,num2 int)(min int ,max int){
if num1 > num2{
min = num2
max = num1
} else{
min = num1
max = num2
}
return
}
func main(){
min,max = MinAndMax(10,20)
fmt.Printf("min=%d,max=%d",min,max)
}
2.4递归函数
递归指函数可以直接或间接的调用自身
//通过循环实现1+2+3....+100
func Test1() int{
i := 1
sum := 0
for i = 1;i<=100;i++{
sum +=1
}
return sum
}
//通过递归实现1+2+3...+100
func Test02(num int) int {
if num == 1{
return 1
}
return num + Test02(num-1)
}
func main(){
fmt.Println(Test1())
fmt.Println(Test2(100))
}
3.函数类型
在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。
type FuncType func(int,int)int //声明一个函数类型,func后面没有函数名
func Cale(a,b int,f FuncType)(result int){ //函数中哟哟一个参数类型为函数类型 f
result = f(a,b)
return
}
func Add(a,b int)int{
return a+b
}
func Minus(a,b int)int{
return a-b
}
func mian(){
result := Cale(1,2,Add) #计算加法
var f FuncType = Minus
fmt.Println("result = ",f(10,2))
}
4.匿名函数与闭包
所谓闭包就是一个函数“捕获”了和它在同一作用域的其他常量和变量。这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者常量,它不关心中文系为捕获了的变量和常量是否已经超出了作用域,所以只要闭包还在使用它,这些常量就还会存在。
在Go语言里,所有的匿名函数都是闭包。
func main(){
i := 0
str := "mike"
//方式一
f1 := func(){ //匿名函数,无函数名无参数无返回值
//引用到函数外的变量
fmt.Printf("方式1:i=%d,str = %s\n",i,str)
}
f1() //函数调用 相当于给这个函数命名为f1
//方式一的另一种方式 声明了一个FuncType函数类型,然后f2的类型设为functype类型并且赋值为f1
type FuncType func() //声明为函数类型,无参无返回值
var f2 FuncType = f1
f2() 调用
}
//方式2 初始化的同时赋值
var f3 FuncType = func(){
fmt.Printf("方式2:i = %d,str = %s\n",i,str)
}
f3() //函数调用
//方式3
func(){ //匿名函数,无参数无返回值
fmt.Printf("方式3:i = %d ,str = %s\n",i,str)
}() //写完后在后面直接写(),直接执行该匿名函数
//方式4 匿名函数,有参数有返回值
v := func(a,b,int)(result int){
result = a + b
return
}(1,1) //传入1,1 直接调用此匿名函数并且传入参数
闭包捕获外部变量特点:
func main(){
i := 10
str := "mike"
func(){
i = 100
str = "go"
//内部: i = 100,str = go
}() //直接调用此匿名函数
//外部: i = 100, str = go
}
函数返回值为匿名函数
//squares返回一个匿名函数,func() int
//该匿名函数每次被滴啊用时都会返回下一个数的平方
func squares() func() int{
var x int
return func() int{ //匿名函数
x++ //捕获外部变量
return x*x
}
}
func main(){
f := squares()
fmt.Println(f()) // 1
fmt.Println(f()) // 4
fmt.Println(f()) // 9
fmt.Println(f()) // 16
}
squares返回另一个类型为func()int类型的函数。对squares的一次调用会生成一个局部变量x并返回一个匿名函数。
变量的声明周期不由它的作用域决定:squares返回后,变量x仍然隐式的存在于f中。
5 延迟调用defer
5.1 defer作用
关键字defer用于延迟一个函数或者方法(或者当前创建的匿名函数)的执行。注意,defer语句中只能出现在函数或者方法的内部。
func mian(){
fmt.Println("this is a test")
defer fmt.Println("this is a defer") //main结束前调用
}
/*
运行结果:
this is a test
this is a defer
*/
defer语句经常被用于处理成对的操作,如打开,关闭,连接,断开连接,加锁,释放锁。通过defer机制,不论函数逻辑多复杂都能保证在任何执行路径下,资源被释放。释放资源的defer应该直接跟在请求资源的语句后面。
5.2 多个defer执行顺序
如果一个函数中有个defer语句,它们会以后进先出的顺序执行。即使出错,这些调用依旧会被执行。
func test(x int){
fmt.Println(100 / x) //x为0时,产生异常
}
func main(){
defer fmt.Println("aaaaaa")
defer fmt.Println("bbbbbb")
defer test(0)
defer fmt.Println("ccccccc")
}
/*
运行结果:
cccccc
bbbbbb
aaaaaa
panic: runtime error :integer divide by zero
*/
5.3defer和匿名函数结合使用
func main(){
a,b := 10,20
defer func(x int){ //a以值传递的方式传给x
fmt.Println("defer:"x,b) //b 闭包使用
}(a)
a += 10
b += 100
fmt.Printf("a = %d,b = %d\n",a,b)
/*
运行结果:
a = 20,b = 120
defet:10, 120
*/
}