go中的自定义函数(只懂helloword的小白对于go的基础认识-3) |青训营

40 阅读5分钟

函数自定义

以下为函数定义格式:

func function_name( [parameter list] ) [return_types]{
   //这里写函数体
}

实例(比较两个数的大小并返回最大值)

func max (num1,num2 int) int {
   var result int
   if num1>num2{
      result = num1
   }
   else {
      result = num2
   }
   return result
}

对函数的调用方式与c语言相同 Go函数可以返回多个值

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}

函数参数传递有着值传递和引用传递两种传参方式 值传递是函数所做的修改不会改变实际参数的值,而引用(地址)传递则是会改变参数的值

type

type 关键字可以自定义类型

type Myint int //类型定义
//此时Myint已经是一个全新的类型了,不过它的特征或者说属性和int类型完全相同
type Myint= int//类型别名
//Myint此时就是int类型,而非一个全新的类型,此时他所指代的任然是int类型,只是相当于换了个名称称呼in而已

函数,具体格式如下

type calculation func(int, int) int
func add(a,b int)int{
   return a+b
}
#定义函数类型后可以声明这种类型的变量并对其赋值
var c calculation
a:=1
b:=2
c=add(a,b)
#赋值后可以直接向调式函数一样使用这个变量

golang函数的骚

与c不同的是,go语言的函数也能作为形参或者返回类型(????)使用

//函数作为参数传入另一个函数
func add(x, y int) int {
	return x + y
}
func calc(x, y int, op func(int, int) int) int {
	return op(x, y)
}
//上面的声明:op作为形参名,后面的func(int,int) int表示op是一个需要两个int型变量传入返回值也是int的一个函数
func main() {
	ret2 := calc(10, 20, add)
//这里直接向calc中传入了add函数
	fmt.Println(ret2) //30
}

个人思考:结合上面的"type calculation func(int, int) int","op func(int, int) int"这一句可以写为op calculation

//函数作为返回类型的使用
func do(s string) (func(int, int) int, error) {
	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("无法识别的操作符")
		return nil, err
	}
}

匿名函数与闭包

golang中还存在一种匿名函数

主要使用场景就是闭包,有两种调用方式

  • 赋值给变量进行调用(闭包的使用场景)
    var f=func(x int) int{
       x+=1
       return x
    }
    fmt.Println(f(2))//3
    
  • 在函数后直接加上括号并传入值(闭包的原理基础?)
    
    fmt.Println(
       func(x int) int{
       x+=1
       return x
       }(2)
    )//3
    

闭包的一大特征是以一个或多个函数作为另一个函数的返回值,即假设有一个C函数,他的返回值可以由函数A、B、D....等多个函数构成,此时若将声明的C函数赋值给变量V(假设此时C函数仅有1个返回值),这时V就可以作为返回的函数A被正常调用,若此时有一个变量V1,位于函数A外,函数C内,则V1的值在V被释放之前不会被释放

exp1:不带形参的函数C(返回值为一个带形参的的函数A)

package main

import "fmt"

func adder() func(int) int {
	var x int = 0
	return func(y int) int {
		x += y

		return x
	}

}
func main() {
	var f = adder()
	fmt.Println(f(10), "/t", f(20), "/t", f(30))//10 30 60

}

上面的x就相当于变量V1,f相当于变量V,由于变量f位于main()函数体中,故直到main函数执行完成之前变量f存储的值不会被释放,x也包含在f内。(有点全局变量(伪)的意思)
exp2带形参的函数C(返回值为一个带形参的的函数A)

package main

import "fmt"

func adder(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}

}
func main() {
	var f = adder(10)
	fmt.Println(f(10), "/t", f(20), "/t", f(30))//20 40 70

}

exp3:带参数的函数C(返回值为多个带参数的函数,A、B、C...)

func calc(base int) (func(int) int, func(int) int) {
	add := func(i int) int {
		base += i
		return base
	}

	sub := func(i int) int {
		base -= i
		return base
	}
	return add, sub
}

func main() {
	f1, f2 := calc(10)
	fmt.Println(f1(1), f2(2)) //11 9
	fmt.Println(f1(3), f2(4)) //12 8
	fmt.Println(f1(5), f2(6)) //13 7
}

函数体中的defer

Go中defer的用法是在放在一般语句的前面,在函数即将返回时,defer语句将按照定义的逆序执行,说人话就时在函数执行完其他所有除defer以外的语句后执行defer,且越早定义的defer语句越后执行
go语言的return(返回)函数的返回机制在底层的操作为先将要返回的变量的值赋予返回值,然后再执行RET命令(大概是返回操作?),而defer语句的执行时间就位于赋值以后,RET指令之前。如下图

用处:可以方便的将资源清理的语句放在函数中的任何位置,反正执行顺序一样

内置函数

内置函数介绍
close关闭各种channel(通道)
len获取长度
make分配内存,只用于map、slice、chan三种类型的内存分配
new也是分配内存
append追加元素到数组或切片之中
panic处理错误
recover处理错误,但只能写在defer调用的函数里面
make和new

new函数只接受一个参数,这个参数是一个类型,并且返回一个指向该类型内存地址的指针。
new函数会把分配的内存置为零,也就是类型的零值
make函数仅用与map、chan、slice三种类型的分配,且返回值也是这三种类型本身而非他们的指针

make 只能用来分配及初始化类型为 slice、map、chan 的数据。new 可以分配任意类型的数据;
new 分配返回的是指针,即类型 Type。make 返回引用,即 Type;
new 分配的空间被清零。make 分配空间后,会进行初始化;常用的任然是make
*