go语言基础之函数

欢迎来我的个人博客:fizzyi

自定义函数

1.定义格式

函数构成代码执行的逻辑结构。在Go语言中,函数的基本组成为:关键字func,函数名,参数列表,返回值,函数体和返回语句。

Go语言函数定义格式如下:


func FuncName(/*参数列表*/)(o1 type1,o2 type2/*返回类型*/) 

//函数体 

return v1,v2//返回多个值 

返回类型说明:

  1. 上面返回值声明了两个变量名o1和o2(命名返回参数),这个不是必须,可以只有类型没有变量名

  2. 如果只有一个返回值且不声明返回值变量,那么你可以省略,包括返回值的括号

  3. 如果没有返回值,那么就直接省略最后的返回信息。

  4. 如果有返回值,那么必须在函数的内部添加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
    */
}

你可能感兴趣的:(go语言基础之函数)