侧边栏壁纸
博主头像
船长博主等级

专注于云原生运维,致敬每个爱学习的你

  • 累计撰写 35 篇文章
  • 累计创建 10 个标签
  • 累计收到 10 条评论

Golang 函数

船长
2022-01-29 / 0 评论 / 0 点赞 / 351 阅读 / 2,891 字
温馨提示:
本文最后更新于 2022-01-29,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

概述

函数是组织好的、可重复使用的执行特定任务的代码块。它可以提高应用程序的模块性和代码的重复利用率。Go 语言从设计上对函数进行了优化和改进,让函数使用起来更加方便。因为Go语言的函数本身可以作为值进行传递,既支持匿名函数和闭包,又能满足接口,所以 Go 语言的函数属于一等公民。

函数的定义

Go语言中定义函数使用func关键字,具体格式如下:

func 函数名(参数)(返回值){
    函数体
}
  • 由字母、数字、下划线组成。但函数名的第一个字母不能是数字。在同一个包内,函数名也称不能重名(包的概念详见后文)。
  • 参数:参数由参数变量和参数变量的类型组成,多个参数之间使用,分隔。
  • 返回值:返回值由返回值变量和其变量类型组成,也可以只写返回值的类型,多个返回值必须用()包裹,并用,分隔。
  • 函数体:实现指定功能的代码块。

用函数定义一个求两个数之和的函数:

func sum(x int, y int) int {
	return x + y
}

func main() {
	s := sum(1,2)
	fmt.Println(s)
}

运行结果:
3

参数

类型简写

函数的参数中如果相邻变量的类型相同,可以省略类型,如下:

func Sum(x, y int) int {
	return x + y
}

上面的代码中,Sum函数有两个参数,这两个参数的类型均为int,因此可以省略x的类型,因为y后面有类型说明,x参数也是该类型。

可变参数是指函数的参数数量不固定。Go语言中的可变参数通过在参数名后加...来标识。

注意:可变参数通常要作为函数的最后一个参数。

可变参数

可变参数就是指函数的参数数量不固定。Go语言中的可变参数通过在参数名 后加...来标识。

注意:可变参数通常要作为函数的最后一个参数。

package main

import "fmt"

func intSum2(x ...int) int {
	fmt.Println(x) //x是一个切片
	sum := 0
	for _, v := range x {
		sum = sum + v
	}
	return sum
}
func main() {
	ret1 := intSum2()
	ret2 := intSum2(10)
	ret3 := intSum2(10, 20)
	ret4 := intSum2(10, 20, 30)
	fmt.Println(ret1, ret2, ret3, ret4) //0 10 30 60
}


运行结果:
[]
[10]
[10 20]
[10 20 30]
0 10 30 60

返回值

Go语言中通过return关键字向外输出返回值。

多返回值

Go语言中函数支持多返回值,函数如果有多个返回值时必须用()将所有返回值包裹起来。

func add(a, b int) (c int) {
	c = a + b
	return
}

func calc(a, b int) (sum int, avg int) {
	sum = a + b
	avg = (a + b) / 2

	return
}

func main() {
	var a, b int = 1, 2
	c := add(a, b)
	sum, avg := calc(a, b)
	fmt.Println(a, b, c, sum, avg)
}


运行结果:
1 2 3 3 1

返回值命名

函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return关键字返回。

package main

import "fmt"

func calc(x, y int) (sum, sub int) {
	sum = x + y
	sub = x - y
	return
}


func main() {
	s,b := calc(8,9)
	fmt.Println(s,b)

}

运行结果:

17 -1

返回值补充

当我们的一个函数返回值类型为slice时,nil可以看做是一个有效的slice,没必要显示返回一个长度为0的切片

func someFunc(x string) []int {
	if x == "" {
		return nil // 没必要返回[]int{}
	}
	...
}

匿名函数

匿名函数是指不需要定义函数名的一种函数实现方式。1958年LISP首先采用匿名函数。

在Go里面,函数可以像普通变量一样被传递或使用,Go语言支持随时在代码里定义匿名函数。

匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。

func main() {
	// 将匿名函数保存到变量
	add := func(x, y int) {
		fmt.Println(x + y)
	}
	add(10, 20) // 通过变量调用匿名函数

	//自执行函数:匿名函数定义完加()直接执行
	func(x, y int) {
		fmt.Println(x + y)
	}(10, 20)
}

运行结果:
30
30

闭包函数

闭包是由函数及其相关引用环境组合而成的实体 (即:闭包=函数+引用环境)。

“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

package main

import "fmt"

func test() func(int) int{
	var x int
	return func(y int) int{
		x +=y
		return x
	}
}

func main() {
	var bai = test()
	fmt.Println(bai(10))
	fmt.Println(bai(20))
	fmt.Println(bai(30))
}

运行结果:
10
30
60

变量bai是一个函数并且它引用了其外部作用域中x变量,此时bai就是一个闭包。在bai的生命周期内,变量x也一直有效;

外部引用函数参数局部变量:

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

func main() {
	var bai = test(90)
	fmt.Println(bai(10))
	fmt.Println(bai(20))
	fmt.Println(bai(30))
}

运行结果:
100
120
150

返回多个闭包:

func test(x int) (func(y int) int, func(b int) int){
	y_int := func(y int) int{
		x = x + y
		return x
	}
	b_int := func(b int) int {
		b = x - b
		return b
	}
	return y_int,b_int
}

func main() {
	var b1,b2 = test(90)
	fmt.Println(b1(10),b2(10))
	fmt.Println(b1(20),b2(20))
	fmt.Println(b1(30),b2(30))
}

运行结果:
100 90
120 100
150 120

延迟调用defer

Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。

func main() {
	defer fmt.Println("1111")
	fmt.Println("2")
	fmt.Println("3")
	fmt.Println("4")

}

运行结果:
2
3
4
1111
0

评论区