函数定义

函数的基本组成:关键字func,函数名,参数列表,返回值,函数体,返回语句。

示例如下:

func Add(a int, b int) (ret int, err error)  {
if a < 0 || b < 0 {
err = errors.New("should be non-negative numbers")
return
}
return a + b, nil // 支持多重返回值
}

如果参数列表中若干个相邻的参数类型相同,可以省略前面参数的类型声明:

// 参数列表中a,b的类型相同,省略了a参数的类型声明
func Add(a, b int) (ret int, err error) {
// ...
}

如果返回值列表中多个返回值的类型相同,也可以使用同样的方式合并。

如果函数返回值只有一个,不用声明返回值变量名:

// 函数只有一个返回值,不用声明返回值变量名
func Add2(a, b int) int {
// ...
}

函数调用

在调用函数前,需要导入函数所在的包:

import "mymath"// 假设Add被放在一个叫mymath的包中
c := mymath.Add(1, 2)

注意: Golang中函数名字的首字母大小写不仅仅是风格,更直接体现了该函数的可见性。

规则:小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。这个规则也适用于类型和变量的可见性。

不定参数

不定参数是指函数的参数个数为不定数量。

不定参数类型

将函数定义为接收不定参数类型:

func myFunc(args ...int) {
for _, arg := range args {
fmt.Print(arg, " ")
}
fmt.Println()
}

调用:

// 传递给函数的参数个数不固定
myFunc(1)
myFunc(1, 2)

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

不定参数的传递

假设有一个变参函数myFun2:

func myFun2(args ...int) {
// ...
}

如下示例展示了如何向其传递变参:

func myFunc(args ...int) {
// 按原样传递
myFun2(args...)
// 传递参数片段
myFun2(args[1:]...)
}

任意类型的不定参数

如果希望传递任意类型的参数,可以指定类型为interface{}。

示例:

// 不定参数类型
func myPrintf(args ...interface{}) {
for _, arg := range args {
switch arg.(type) {
case int:
fmt.Println(arg, "is an integer")
case string:
fmt.Println(arg, "is a string")
case int64:
fmt.Println(arg, "is a int64")
default:
fmt.Println(arg, "is an unknown type")
}
}
} func main() {
var v1 int = 1
var v2 int64 = 2
var v3 string = "hello"
var v4 float32 = 1.23 // 调用不定参数类型函数
myPrintf(v1, v2, v3, v4)
}

输出:

1 is an integer
2 is a int64
hello is a string
1.23 is an unknown type

多返回值

Golang函数或者成员的方法可以有多个返回值,这个特性能够使我们写出比其他语言更优雅、更简洁的代码。

比如File.Read()函数就可以同时返回读取的字节数和错误信息,如果读取文件成功,则返回值中的n为读取的字节数,err为nil,否则err为具体的出错信息:

func (file *File) Read(b []byte) (n int, err Error)

还可以给返回值命名,就像函数的输入参数一样。

返回值被命名之后,它们的值在函数开始的时候被自动初始化为空。

在函数中执行不带任何参数的return语句时,会返回对应的返回值变量的值。

Golang并不需要强制命名返回值,但是命名后的返回值可以让代码更清晰,可读性更强,同时也可以用于文档。

如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线“_”来跳过这个返回值。

比如下面的代码表示调用者在读文件的时候不想关心Read()函数返回的错误码:

n, _ := f.Read(buf)

匿名函数和闭包

匿名函数是指不需要定义函数名的一种函数实现方式。

匿名函数

在Golang中,函数可以像普通变量一样被传递或使用,可以随时在代码里定义匿名函数。

匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:

func(a, b int, z float64) bool {
return a*b <int(z)
}

匿名函数可以直接赋值给一个变量或者直接执行:

// 定义匿名函数并赋值给变量
f := func(x, y int) int {
return x + y
} // 调用函数
f(1, 2) // 匿名函数的花括号后面直接跟参数列表表示调用匿名函数
func(x, y int) int {
return x + y
}(1,2)

闭包

Golang的匿名函数是一个闭包。

Golang中的闭包同样也会引用到函数外的变量,闭包的实现确保只要闭包还被使用,那么被闭包引用的变量会一直存在。

// 闭包
var j int = 5
a := func() {
var i int = 10
fmt.Printf("i, j: %d, %d\n", i, j)
}
a()
j *= 2
a() // 在这里还会调用闭包函数,被它引用的外部变量j一直存在,所以其只会在两次闭包调用时不同

输出:

i, j: 10, 5   # 第一次调用闭包函数时,变量j的值未变化
i, j: 10, 10 # 第二次调用闭包函数时,变量j的值已经发生变化

学习go语言编程之函数的更多相关文章

  1. 如何轻松学习C语言编程!

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  2. LINUX下C语言编程调用函数、链接头文件以及库文件

    LINUX下C语言编程经常需要链接其他函数,而其他函数一般都放在另外.c文件中,或者打包放在一个库文件里面,我需要在main函数中调用这些函数,主要有如下几种方法: 1.当需要调用函数的个数比较少时, ...

  3. 学习go语言编程系列之定义变量

    package main import ( "fmt" "math") func main() { // 1. 定义变量名age,不初始化,使用对应类型的默认值 ...

  4. 学习go语言编程系列之helloworld

    1. 下载https://golang.org/dl/ # Go语言官网地址,在国内下载太慢,甚至都无法访问.通过如下地址下载:https://golangtc.com/download. 2. 安装 ...

  5. C语言编程中函数指针的定义及使用

    C语言中函数指针的定义: typedef int (*funcPtr)(int, int)表示定义了一个函数指针funcPtr,这个函数指针只能指向如下: int add(int, int).int ...

  6. c#基础语言编程-常用函数

    类型转换Convert Convert考虑数据意义的转换. Convert是一个加工.改造的过程.在使用Convert的转换过程中不会返回异常,当遇到类型转换的不知道的时候,用Convert找找. T ...

  7. linux中c语言编程main函数和参数

    linux下main函数的的标准调用函数的标准形式 int main(int char,char *argv[]) 在main函数的两个参数中,argc必须是整型变量,其是命令行的参数的数目,argv ...

  8. C语言编程漫谈——main函数

    写在前面 促使我写这篇文章是因为我这几天找了几个一样是大三的同学,与我相同专业相同方向(物联网)的人,除了@小胡同的诗,基本没有什么其他人会现在看起来很简单的编程题目了.问了一下其他同学,他们大部分都 ...

  9. Linux C语言编程学习笔记 (1)进程控制入门

    想进行Linux系统开发已经很久了,一直没有付诸实践.今日终于开始学习Linux下的C语言编程,研究一天,终于大概弄明白了Linux系统进程管理的一些基本概念和编程方法,总结下来以方便大家学习和自己实 ...

  10. C/C++编程笔记:C语言写推箱子小游戏,大一学习C语言练手项目

    C语言,作为大多数人的第一门编程语言,重要性不言而喻,很多编程习惯,逻辑方式在此时就已经形成了.这个是我在大一学习 C语言 后写的推箱子小游戏,自己的逻辑能力得到了提升,在这里同大家分享这个推箱子小游 ...

随机推荐

  1. 【转帖】You can now run a GPT-3-level AI model on your laptop, phone, and Raspberry Pi

    https://arstechnica.com/information-technology/2023/03/you-can-now-run-a-gpt-3-level-ai-model-on-you ...

  2. [转帖]耗时几个月,终于找到了JVM停顿十几秒的原因

    https://www.cnblogs.com/codelogs/p/16060792.html   原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介# 最近我们系 ...

  3. SAP FICO 前台财务过账、预制功能分开

    最近遇到一个变态要求,FB01 等涉及过账功能 要求根据'权限'判断用户是否有过账的功能.以下实现会有遗漏场景: 实现:hide 'SAVE'按钮 (ok_code = 'BU'). 根据状态栏设置' ...

  4. css伪类和伪元素在项目中的使用-红色*显示

    CSS使用伪类给表单添加星号 <style type="text/css"> .form-item label::before { content: '*'; colo ...

  5. jenkins 安装与构建过程中的系列问题

    一.插件安装遇到的依赖问题 插件安装分为在线安装和离线安装 1.在线安装 搜索要安装的插件,然后进行安装即可 2.离线安装hpi文件 使用该方法安装插件每次只能安装一个插件,且如果插件之间存在依赖性则 ...

  6. windbg-windows调试工具来抓端游crash dump

    windbg下载有两种方式: Install WinDbg - Windows drivers | Microsoft Learn 从微软应用商店下载 dump上的windows的局部变量解析部分进行 ...

  7. Pytest 源码解读 [1] - [pluggy] 核心设计理念浅读

    背景: Pytest 是一个功能强大的 Python 测试框架,它使用了一个名为 "pluggy" 的插件系统来扩展其功能.在 Pytest 的源码中,pluggy 模块负责实现插 ...

  8. NLP涉及技术原理和应用简单讲解【一】:paddle(梯度裁剪、ONNX协议、动态图转静态图、推理部署)

    参考链接: https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/advanced/gradient_clip_cn.html 1. ...

  9. python中--try except 异常捕获以及正则化、替换异常值

    1.异常处理过程 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exceptio ...

  10. 多智能体强化学习算法【三】【QMIX、MADDPG、MAPPO】

    相关文章: 常见多智能体强化学习仿真环境介绍[一]{推荐收藏,真的牛} 多智能体强化学习算法[一][MAPPO.MADDPG.QMIX] 多智能体强化学习算法[二][MADDPG.QMIX.MAPPO ...