函数定义

函数的基本组成:关键字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. Nginx双层域名时 iframe嵌入/跳转页面的处理过程

    Nginx双层域名时 iframe嵌入/跳转页面的处理过程 背景 两年前在上一家公司内遇到一个Nginx的问题 当时的场景是 双层nginx代理时(一层域名侧, 一层拆分微服务的网关层) 程序里面会打 ...

  2. [转帖]011 Linux 打包与解压 tar

    https://my.oschina.net/u/3113381/blog/5429977 01 压缩.打包命令有哪些? Linux 上有着各种压缩.打包的工具:tar.gzip.zip.7z,而 t ...

  3. Redis IO多线程的简要测试结果

    Redis IO多线程的简要测试结果 摘要 最近想简单确认一下IO多线程的对吞吐量的提升情况. 正好手头有鲲鹏的机器, 所以想直接进行一下验证 顺便用一下4216 进行一下对比. 发现 在CPU核心比 ...

  4. 一文详解 Netty 组件

    作者:京东物流 张弓言 一.背景 Netty 是一款优秀的高性能网络框架,内部通过 NIO 的方式来处理网络请求,在高负载下也能可靠和高效地处理 I/O 操作 作为较底层的网络通信框架,其被广泛应用在 ...

  5. fbx查看软件

    对于3D的模型资源,比如fbx文件,除了使用专业的软件查看外,比如Unity3D,vs2015及更高版本,maya,3DMax等等,有没有更加轻量的软件可以查看fbx的内容呢? win10自带 win ...

  6. vim 从嫌弃到依赖(14)——快速跳转

    之前介绍过众多的motion,根据移动范围来排序的话有 l.e.w.j等等,但是面对那么长的代码文件,仅仅使用这几个简单的motion不知道要移动多少次才能找到我想要的代码,这个速度有时候还不如我用鼠 ...

  7. 《字节码编程》PDF107页,11万字。既然市面缺少ASM、Javassist、Byte-buddy成体系的学习资料,那我来!

    作者:小傅哥 博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 让人怪不好意思的,说是出书有点膨胀,毕竟这不是走出版社的流程,选题. ...

  8. SpringCloud-04-http客户端Feign

    http客户端Feign 1.Feign的介绍 Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现ht ...

  9. MySQL8.0清空binlog

    环境 centos7.9 mysql  Ver 8.0.32 登录MySQL,查看binlog日志 #查看binlog日志开启状态,log_bin值为ON表示开启状态 mysql> show v ...

  10. 【栈和队列】纯C实现栈和队列以及其基本操作-宝藏级别数据结构教程【保姆级别详细教学】

    [栈和队列]栈和队列的C语言实现-宝藏级别数据结构教程-超详细的注释和解释 先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记 ...