【Go语言】Go语言中的函数

Go语言中的函数

Go语言中,函数主要有三种类型:

  • 普通函数

  • 匿名函数(闭包)

  • 类方法

1 函数定义

Go语言函数的基本组成包括:关键字func、函数名、参数列表、返回值、函数体和返回语句。Go语言是强类型语言,无论是参数还是返回值,在定义函数时,都需要声明其类型。

如下是Go语言中函数的一个简单示例:

// 参数类型 int
// 返回类型 int
func add(a, b int) int  {return a + b
}

2 函数调用

2.1 调用同一个包定义的函数

如果函数在同一个包中,只需要直接调用即可:

func add(a, b int) int  {return a + b
}func main()  {fmt.Println(add(1, 2))  // 3
}

2.2 调用其他包定义的函数

如果函数是在不同的包中,需要先导入该函数所在的包,然后才能调用该函数,例如 Add 函数在 calculator 包中。

package calculatorfunc Add(a, b int) int  {return a + b
}

在 main 包中调用Add函数。

package mainimport ("fmt""calculator"
)
func main()  {fmt.Println(calculator.Add(1, 2))   // 3
}

注意:在调用其他包定义的函数时,只有这个函数名首字母大写的才可以被调用,例如函数名为add就会出现如下情况:

2.3 系统内置函数

Go语言中内置了常用的函数,如下所示

名称说明
close用于在管道通信中关闭一个管道
lencaplen 用于返回某个类型的长度(字符串、数组、切片、字典和管道),cap 则是容量的意思,用于返回某个类型的最大容量(只能用于数组、切片和管道)
newmakenewmake 均用于分配内存,new 用于值类型和用户自定义的类型(类),make 用于内置引用类型(切片、字典和管道)。它们在使用时将类型作为参数:new(type)make(type)new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针,可以用于基本类型:v := new(int)make(T) 返回类型 T 的初始化之后的值,所以 make 不仅分配内存地址还会初始化对应类型。
copyappend分别用于切片的复制和动态添加元素
panicrecover两者均用于错误处理机制
printprintln打印函数,在实际开发中建议使用 fmt 包
complexrealimag用于复数类型的创建和操作

3 参数传递

3.1 按值传参

Go语言默认使用按值传参来传递参数,也就是传递参数值的一个副本,函数收到传递进来的参数后,会将参数值拷贝给声明该参数的变量(也叫做形式参数,简称形参),如果在函数体中有对参数值做修改,实际上修改的是形参值,这不会影响到实际传递进来的参数值(也叫实际参数,简称实参)。

示例代码如下:

// a,b 是形式参数
func add(a, b int) int  {a *= 2b *= 3return a + b
}
func main()  {x, y := 1, 2// x,y 是实际参数z := add(x, y)// z的值是x*2+y*3=8,但x,y的值并未改变fmt.Printf("add(%d, %d) = %d\n", x, y, z)  
}

3.2 引用传参

如果需要实现在函数中修改形参值的同时改变实参,需要引用传参来实现,此时传递给函数的参数是一个指针,而指针代表的是实参的内存地址,修改指针引用的值即修改变量内存地址中存储的值,因此实参的值也会被修改。

示例代码如下:

// a,b 是形式参数
func add(a, b *int) int  {*a *= 2*b *= 3return *a + *b
}
func main()  {x, y := 1, 2// x,y 是实际参数z := add(&x, &y)// z的值是x*2+y*3=8,由于我们直接修改了内存超出地址的值,因此x变为2,y变为6fmt.Printf("add(%d, %d) = %d\n", x, y, z)  
}

在函数调用时,像切片(slice)、字典(map)、接口(interface)、通道(channel)这样的引用类型默认使用引用传参。

4 变长参数

变长参数指的是函数参数的数量不确定,可以按照需要传递任意数量的参数到函数。

4.1 基本定义和传值

只需要在参数类型前加上 ... 前缀,就可以将该参数声明为变长参数。

// 函数Myfunc()接受任意数量的参数,这些参数的类型全部是int
func Myfunc(numbers ...int){for _,number := range numbers {fmt.Println(number)}
}
// 函数可以按照如下方式调用:
Myfunc(1,2,3,4,5,6)
Myfunc(1,2,3)

函数调用测试:

变长参数还支持传递一个 []int 类型的切片,传递切片时需要在末尾加上 ... 作为标识,标识对应的参数类型是变长参数:

slice := []int{1,2,3,4,5,6}
Myfunc(slice...)
Myfunc(slice[1:3]...)

注:...type 只能作为函数的参数类型存在,并且必须是函数的最后一个参数。

4.2 任意类型的变长参数(泛型)

Go语言中,可以通过指定变长参数类型为 interface{} 来实现参数的任意类型传递。

代码实现如下:

// 变长参数,可以传递任意个数的参数,类型无要求
func Myfunc2(params ...interface{}) {for _, param := range params {fmt.Println(param)}
}

5 多返回值

5.1 多返回值

Go语言中,函数能够支持多返回值,经常用在程序出错的时候。

代码示例如下:

// 函数定义
func AddFunc(a, b *int) (int, error) {if *a < 0 || *b < 0 {err := errors.New("仅支持非负整数的相加")return 0, err}return *a + *b, nil
}
// 函数调用
x, y := -1, 2
z, err := function.AddFunc(&x, &y)
if err != nil {fmt.Println(err.Error())return
}
fmt.Printf("%d + %d = %d", x, y, z)

5.2命名返回值

函数设置多返回值时,还可以对返回值进行变量命名,这样就可以直接在函数中对返回值变量进行赋值,而不需要按照指定的返回值格式返回多个变量。

代码示例:

// 函数定义
func AddFunc2(a, b *int) (c int, err error) {if *a < 0 || *b < 0 {err = errors.New("仅支持非负整数的相加")return}c = *a + *breturn
}
// 函数调用
x, y := -1, 2
z, err := function.AddFunc2(&x, &y)
if err != nil {fmt.Println(err.Error())return
}
fmt.Printf("%d + %d = %d", x, y, z)

6 匿名函数与闭包

6.1 匿名函数的定义和使用

匿名函数是一种没有指定函数名的函数声明方式。

代码示例如下:

func(a,b int) int {return a+b
}

Go语言中,匿名函数也可以赋值给一个变量或者直接执行:

// 将匿名函数赋值给变量
sum := func(a,b int) int {return a+b
}
// 调用匿名函数 add
fmt.Print(sum(1,2))// 也可以在定义的时候,直接调用匿名函数
func(a,b int){fmt.Println(a+b)
} (1,2)

6.2 匿名函数与闭包

闭包:指引用了外部函数作用域中的变量的函数。也即,闭包是一个函数及其相关引用环境的组合。

匿名函数和闭包的关系:匿名函数可以用来创建闭包,当一个匿名函数引用了外部函数作用域中的变量时,该匿名函数就成了一个闭包。

6.3 匿名函数的使用场景

6.3.1 保证局部变量的安全性

匿名函数内部声明的局部变量无法从外部修改,从而确保了安全性(类似类的私有属性)。

代码示例如下:

var j int =1
f := func(){var i int = 1fmt.Println(i,j)
}
f()
j += 2
f()

如上代码运行所示,匿名函数引用了外部变量j,所以同时也是个闭包,变量f指向的闭包引用了局部变量i和j,i在闭包内定义,其值被隔离,不能从外部修改变量,j在闭包外定义,所以可以从外部修改,闭包只是引用了变量j的值。

6.3.2 将匿名函数作为函数参数

匿名函数除了可以赋值给普通变量外,还可以作为函数参数传递到函数中进行调用,就像普通数据类型一样。

代码示例:

add := func(a, b int) int {return a + b
}
func(call func(int, int) int) {fmt.Println(call(1, 2))
}(add)

6.3.3 将匿名函数作为函数返回值

Go语言中,匿名函数也能够作为返回值使用。

代码示例:

func defaultAdd(a, b int) func() int {return func() int {return a + b}
}// 此时返回的是匿名函数
addFunc := defaultAdd(1, 2)
// 这里才会真正的执行加法操作
fmt.Println(addFunc())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/540586.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

普林斯顿算法讲义(四)

原文&#xff1a;普林斯顿大学算法课程 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 6.1 事件驱动模拟 原文&#xff1a;algs4.cs.princeton.edu/61event 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 本章节正在建设中。 根据弹性碰撞的法则使用事件驱动…

C语言指针与数组(不适合初学者版):一篇文章带你深入了解指针与数组!

&#x1f388;个人主页&#xff1a;JAMES别扣了 &#x1f495;在校大学生一枚。对IT有着极其浓厚的兴趣 ✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享. &#x1f60d;希望我的文章对大家有着不一样的帮助&#xff0c;欢迎大家关注我&#xff0c;我也会回…

Dev Studio 安装与使用

目录 一、DevEco Studio 下载 二、DevEco Studio 诊断开发环境 2.1 配置NPM代理 2.2 ohpm 报错 三、启用中文化插件 四、构建第一个ArkTS应用&#xff08;Stage模型&#xff09; 4.1 创建ArkTS工程 4.2 ArkTS工程目录结构&#xff08;Stage模型&#xff09; 4.2 预览项…

TikTok美区再现爆款!“龙蛋”畅销海外!仅一周狂卖近40万美金

当小杨哥、东方甄选开始相继进军TikTok海外电商平台&#xff0c;新一轮的境外风云即将上演... TikTok作为短视频领域的翘楚&#xff0c;其病毒式营销手段让无数产品迅速走红&#xff0c;卖到断货在海外市场也是屡见不鲜&#xff01; 近日&#xff0c;一款独特的 3D 打印龙蛋玩…

WOA-GRU多输入回归预测 | 鲸鱼优化算法-门控循环单元神经网络 | Matlab

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分程序&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&…

(转)已有 vue2 环境下安装 vue3 和vue2并新项目构建

vue2 全局安装过&#xff0c;废话不多说&#xff0c;直接装 vue3 吧 安装 vue3.X 不再需要安装 vue/cli3 的脚手架&#xff0c;而是通过官方推荐的 Vite 开发构建工具快速搭建&#xff0c;具体可查看官方文档 https://vue3js.cn/docs/zh/guide/installation.html#%E5%91%BD%E4…

第六节:使用SMB开发WebService

一、概述 webservice在日常开发中是常用的接口形式&#xff0c;SMB在设计之初就将webservice作为重要的代理协议。在组件库中提供了webservice input和webservice output两个组件&#xff0c;分别用于发布接口和调用接口。 二、发布webservice 在csdnProject工程中创建名为c…

C语言从入门到实战————数组和指针的深入理解

前言 在C语言中&#xff0c;数组和指针有的密切得联系&#xff0c;因为数组名本身就相当于一个指针常量。指针是一个变量&#xff0c;专门用来存储另一个变量的内存地址&#xff0c;通过这个地址可以访问和操作该变量的值&#xff0c;同时也包括数组。数组是一组连续存储的同类…

Dynamic Capacity Service for Improving CXL Pooled Memory Efficiency——论文阅读

IEEE Micro 2023 Paper CXL论文阅读笔记整理 问题 传统系统面对大容量和高带宽内存需求时存在的挑战&#xff1a; 内存墙。计算系统的最新趋势表明&#xff0c;内存性能的提高没有跟上计算性能的步伐。扩展内存带宽和容量的一个可行解决方案是增加中央处理器&#xff08;CPU&…

linux板子vscode gdb 远程调试

板子&#xff1a;hi3556v200 交叉编译工具&#xff1a;arm-himix200-linux 主机&#xff1a;win10虚拟机的ubuntu16.4 gdb:gdb-8.2.tar.gz 1.在ubuntu交叉编译gdb&#xff08;Remote g packet reply is too long解决&#xff09; 建议修改gdb8.2/gdb目录下面的remote.c解决…

ConcurrentHashMap 为什么不能插入 null?

1、典型回答 简单来说&#xff0c;ConcurrentHashMap 不允许插入 null 值是JDK 源码规定的&#xff0c;如下源码所示(此源码基于JDK 1.8)&#xff1a; 从上述源码可以看出&#xff0c;在添加方法的第一句就加了判断&#xff1a;如果 key 值为 null 或者是 value 值为 null&…

电梯机房秀 系列二

上次小伍带大家看了部分机房的照片&#xff0c;并且简单介绍了一下电梯能量回馈装置&#xff0c;小伙伴们表示很新奇&#xff0c;没看够&#xff0c;今天小伍又来了&#xff0c;带大家看一下电梯能量回馈装置到底安装在电梯什么位置。跟着小伍去看看吧。Lets go&#xff01; 电…