当前位置: 首页 > news >正文

Go语言学习(五)-- 函数和闭包

目录

1. 函数的定义和使用

2 实参和形参

3 函数的返回值

4 匿名函数与闭包

4.1 匿名函数

 4.2 闭包

5 不定参函数


1. 函数的定义和使用

Go 语言函数定义格式如下:
func 函数名( 函数参数列表 ) 返回值列表 {
    函数体
    return 返回值列表
}
函数名
理论上是可以随意起名字,最好起的名字见名知意,应该让用户看到这个函数名字就知道这个函数的功能。注意,函数名的后面有个圆换号 () ,代表这个为函数,不是普通的变量名。
形参列表
在定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,因此称它们是形式参数或虚拟参数,简称形参,表示它们并不是实际存在的数据,所以,形参里的变量不能赋 值。
函数体
花括号 { } 里的内容即为函数体的内容,这里为函数功能实现的过程,这和以前的写代码没太大区 别,以前我们把代码写在 main() 函数里,现在只是把这些写到别的函数里。
返回值
函数的返回值是通过函数中的 return 语句获得的, return 后面的值也可以是一个表达式。 Go 语言支持多个返回值。
package main

import "fmt"

//函数定义
func add(a int, b int) int {
	return a + b
}

func swap(a, b int) (int, int) {
	a, b = b, a
	return a, b
}

func main() {
	a := 10
	b := 20
	//函数调用
	value := add(a, b)
	fmt.Println(value)

	//函数调用
	a, b = swap(a, b)
	fmt.Println(a, b) //20,10
}

2 实参和形参

  • 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。
  • 实参出现在主调函数中,进入被调函数后,实参也不能使用。
  • 实参变量对形参变量的数据传递是值传递,即单向传递,只由实参传给形参,而不能由形参传回来给实参。
  • 在调用函数时,编译系统临时给形参分配存储单元。调用结束后,形参单元被释放。
  • 实参单元与形参单元是不同的单元。调用结束后,形参单元被释放,函数调用结束返回主调函数后则不能再使用该形参变量。实参单元仍保留并维持原值。因此,在执行一个被调用函 数时,形参的值如果发生改变,并不会改变主调函数中实参的值。

3 函数的返回值

  • 保证return语句中表达式的值和函数返回类型是同一类型。
  • 如果函数返回的类型和return语句中表达式的值不一致,程序则会报错。
  • return语句的另一个作用为中断return所在的执行函数。
  • 如果函数带返回值,return后面必须跟着值 。

4 匿名函数与闭包

4.1 匿名函数

Go 是支持匿名函数的,即在需要使用函数时。再定义函数 , 匿名函数没有函数名。只有函数体,函
数可以被作为一种类型被赋值给函数类型的变量,匿名函数往往以变量方式被传递。
匿名函数经常被用于实现回调函数 , 闭包等

匿名函数定义

匿名函数的定义就是: 没有名字的普通函数

func (参数列表) (返回值列表) { 
    函数体 
}
匿名函数的调用
既然定义了一个匿名的函数,那我们该如何去调用这个函数呢?没有名字怎么调用啊??
  • 在定义时调用匿名函数
func main() {
	adder := func(a int) int {
		//计算1+2+....+a
		var sum int
		for i := 1; i <= a; i++ {
			sum += i
		}
		return sum
	}

	//此时adder就是一个函数类型的变量可以直接来使用
	sum := adder(10)
	fmt.Println(sum)
}
  • 匿名函数做回调函数

回调函数 ,或简称 回调 Callback call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用
func Adder(f func(int2 int) int, a int) int {
	return f(a)
}

func main() {
	adder := func(a int) int {
		//计算1+2+....+a
		var sum int
		for i := 1; i <= a; i++ {
			sum += i
		}
		return sum
	}
	adderEven := func(a int) int {
		var sum int
		for i := 0; i <= a; i += 2 {
			sum += i
		}
		return sum
	}
	println(Adder(adder, 10))
	println(Adder(adderEven, 10))
}

 4.2 闭包

Go 语言支持匿名函数,可作为闭包。匿名函数是一个 " 内联 " 语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
以下实例中,创建了函数 getSequence() ,返回另外一个函数。该函数的目的是在闭包中递增 i变量,代码如下:
func getSequence() func() int {
	i := 0
	return func() int {
		i += 1
		return i
	}
}

func main() {
	/* nextNumber 为一个函数,函数 i 为 0 */
	f1 := getSequence()
	/* 调用 f1 函数,i 变量自增 1 并返回 */
	fmt.Println(f1())
	fmt.Println(f1())
	fmt.Println(f1()) //1 2 3
	/* 创建新的函数 f2,并查看结果 */
	f2 := getSequence()
	fmt.Println(f2())
	fmt.Println(f2())//1 2
}

5 不定参函数

在定义函数的时候根据需求指定参数的个数和类型,但是有时候如果 无法确定参数的个数 呢?
例如:计算 n 个整数的和?
在这个要求中,项并没有说清楚到底是有几个整数,那么我们应该怎样确定该函数的参数呢?
可以通过 “ 不定参数列表 “ 来解决这个问题
可以通过如下的方式来定义函数:
func 函数名(数据集合 ...数据类型)
在数据集合后面跟了三个点,就是表示该参数可以接收 0 或多个整数值。所以,这个参数可以想象成是一个集合(类似数学中集合),可以存放多个值。
那么如何进行不定参函数的数据集合计算?
//使用len进行范围遍历 
//计算集合中元素个数 
//len(数据集合) 
for i:=0; i< len(数据集合); i++{ 
    //操作代码 
}
//使用range关键字进行范围遍历 
/* range会从集合中返回两个数 第一个是对应的坐标,赋值给了变量index 第二个就是对应的值,赋值了变量data */
for index,data := range 数据集合{ 
    //操作代码 
}
示例代码
func getSum(nums ...int) int {
	var sum int
	/*for _, num := range nums {
		sum += num
	}*/
	for i := 0; i < len(nums); i++ {
		sum += nums[i]
	}
	return sum
}

func main() {
	println(getSum(1, 2, 3))
	println(getSum(1, 2, 3, 4, 5, 6))
}

golang函数同样支持嵌套调用和递归。就不再一一细说,学过编程语言的小伙伴们学到这里想必也应该能自己去操作嵌套和递归了!赶紧自己去试一试吧!

想要再看看函数递归思想的小伙伴可以去看我的另一篇文章:一文带你了解函数递归

相关文章:

  • 【数据结构】链表其实并不难 —— 手把手带你实现单链表
  • LeetCode每日一题——754. 到达终点数字
  • 有一个是对的,就是坚持去做难的事情。
  • httpClient同步、异步性能对比
  • 吴峰光杀进 Linux 内核
  • 朋友离职了,一周面试了20多场,我直呼内行
  • 创建 MQTT 连接时如何设置参数?
  • C#基础知识
  • 云原生之快速使用Nacos Spring Cloud
  • 什么是GPIO的推挽输出和开漏输出
  • Java 模拟实现 定时器 和 线程池
  • 笔记,正则表达式里的元字符
  • kubernetes 生成认证文件
  • LINUX系统搭建FTP服务器--操作步骤
  • 面试 高频面试题 基础 HTML CSS JS
  • 【Python基础篇020】网络编程初识
  • 11、时序约束
  • 高级IO多路转接之select、poll、epoll
  • Java --- springMVC实现RESTFul案例
  • 大数据相关积累