Go:Fuction

57 阅读3分钟

Function(函数参数传递的时候,值传递(基本类型),go语言中全部都是值传递 指针可以改变值)

1.Function的定义以及初始化

func functionname(parameters list)(return_types){
	content
	return return_types
	//return可以返回单值,可以返回多值,也可以不返回值
}

(1.不返回值

func runForever() {
	for {
		time.Sleep(time.Second)
		fmt.Println("doing")
	}
}

(2.返回多值或单值

func add(a, b int, c float32) (int, error) {
	//go一个函数可以返回多值
	return a + b + int(c), nil
	//不同类型的值相加要格式转化,并不能像c一样直接相加转为float型
}
func main() {
	//go函数支持普通函数,也支持匿名函数、闭包
	/*
		go中函数是“一等公民”
		1.函数本身可以当做变量
		2.函数包含了匿名函数、闭包
		3.函数可以满足接口
	*/
	sum, _ := add(1, 2, 3.14)
	fmt.Println(sum)
}

(3.省略写法

func add(a, b int) (sum int, err error) {
	sum=a+b
	return sum,err
	//return
}

可以直接在return_types中定义返回的变量名和类型,避免了再次在函数体中用var定义的繁琐过程

//return 如果在return_types中已经定义了变量名则可以不在return语句中写返回的变量名,go会直接返回return_types

(4.省略号用法

// 省略号的用法
func add(item ...int) (sum int, err error) {
	for _, value := range item {
		sum += value
	}
	return
}
func main() {
	a := 1
	b := 2
	sum, _ := add(a, b, 3, 4, 5, 6)
	fmt.Println(sum)
}
//1+2+3+4+5+6=21

此时item的本质其实是为一个[]int型的切片

想要切片相加则使用for.range

此时可以往add函数传递多个int型parameters

func add(desc string,item ...int) (sum int, err error) {
	for _, value := range item {
		sum += value
	}
	return
}

如果在item前添加了一个正常的parameter那么该parameter是必须要传递值到该function里的

item可以不传入。

以下是Function的底层逻辑图

当我们在add里面改变a的值时,他只是改变了从main函数里面复制的值,并没有办法改变main函数a的值

func add(a, b int, c float32) (int, error) {
	a = 3
	return a + b + int(c), nil
}
func main() {
	a := 1
	sum, _ := add(1, 2, 3.14)
	fmt.Println(sum)
	fmt.Println(a)

此时可以看到a的值仍然为1

但是返回的值为8,说明在add中a的值为3,也说明了在add函数中更改a的值并不会影响main函数中的a

2.Function的一等公民特性

(1.function可以当作变量使用

func add(item ...int) (sum int, err error) {
	for _, value := range item {
		sum += value
	}
	return
}
	func main() {
	**funcVar := add**
	a := 1
	b := 2
	**sum, _ := funcVar(a, b, 3, 4, 5, 6)**
	fmt.Println(sum)
	fmt.Println(a)
}

Eg:

func cal(op string) func() {
	switch op {
	case "+":
		return func() {
			fmt.Println("这是加法")
		}
	case "-":
		return func() {
			fmt.Println("这是减法")
		}
	default:
		return func() {
			fmt.Println("这是加法")
		}
	}
}
func main{
	cal("+")()
}

(2.function可以作为参数

func add2(a, b int) {
	fmt.Printf("sum is:%d\r\n", a+b)
}
func callBack(y int, f func(int, int)) {
	f(y, 2)
}
func main{
callBack(1, add2)
}

(3.匿名函数

//第一种
callBack(1, func(a, b int) {
		fmt.Printf("total is %d", a+b)
	})
//第二种
localFunc := func(a, b int) {
		fmt.Printf("total is %d", a+b)
	}
	callBack(1, localFunc)

可以直接在函数调用时命名匿名函数

3.Function的闭包特性

func auoIncrement() func() int {
	local := 0
	return func() int {
		local += 1
		return local
	}
}
//闭包
	//有个需求,我希望有个函数每次调用一次返回的结果值都是增加一次之后的值
func main{
	nextFunc := auoIncrement()
	for i := 0; i < 5; i++ {
		fmt.Println(nextFunc())
	}
}

正常情况下在一个函数中访问另一个函数的局部变量是不可行的

但是如果在使用闭包(一个函数中调用一个匿名函数)即可使用原函数的局部变量

可以做到类似于c语言static类型的效果让值累加

nextFunc2 := auoIncrement()
	for i := 0; i < 3; i++ {
		fmt.Println(nextFunc2())
	}

当你再次调用该函数闭包是会发现此时的local值已经清0重新开始运算。

也可以完成的local变量的封装

4.Function中defer的运用

defer多用于关闭数据库,关闭文件,关闭锁

var mu sync.Mutex
mu.Lock()
defer mu.unLock()//defer后面的代码是会放在函数return之前执行的

关于defer的具体应用

        defer fmt.Println("1")
	defer fmt.Println("2")
	defer fmt.Println("main")
	//类似于一个栈的逻辑
	return