函数定义

函数的基本组成:关键字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. vue3关于.sync的用法

    场景描述 我们都知道,子组件是不能够去修改父组件传递过来的数据. 因为如果子组件去修改父组件件传递过来的数据. 会导致数据的应用流向变得难以理解. 但是有些时候,我们需要当子组件的数据变化后,父组件的 ...

  2. minIO系列文章01---MinIO 简介

    MinIO.jpeg MinIO 官网 MinIO 官方GitHub MinIO 官方文档 1.什么是对象存储? 关于对象存储,我们可以看下 阿里云OSS 的解释. 对象存储服务OSS(Object ...

  3. 期盼已久全平台支持-开源IM项目OpenIM之uniapp更新

    国内uniapp使用广泛,OpenIM的uniapp sdk以及文档和demo (https://github.com/OpenIMSDK/Open-IM-Uniapp-Demo)都已更新,本文主要展 ...

  4. 设计模式学习-使用go实现中介者模式

    中介模式 定义 优点 缺点 适用范围 代码实现 参考 中介模式 定义 中介模式(Mediator):用一个中介对象来封装一系列的对象交互.中介者使个各对象不需要显示的相互引用,从而使其藕合松散,而且可 ...

  5. Nmap 扫描并生成HTML报告

    Nmap扫描器,支持生成扫描报告,配合转换模板,可实现自定义转换报告,非常方便. 扫描报告,可以生成如下格式,这是Nmap中自带的格式. nmap -PR -oX lyshark.xml 192.16 ...

  6. 路由react-router-dom的使用

    react-router-dom路由简介 现代的前端页面大多是SPA(单页面应用程序), 也就是只有一个HTML页面的程序,这样用户体验好,服务器压力小,所以更受欢迎.路由是使用单页面来管理原来多页面 ...

  7. 苹果iOS的应用移除主屏幕及恢复找回

    昨天刷到一个苹果iOS系统更换微信图标的,然后就添加了一个,发现那个记录通知数字问题,想恢复回来,所以就有了此文. https://www.cnblogs.com/lzhdim/p/17909867. ...

  8. Oracle预防alert日志过大的脚本:del_alertlog.sh

    Oracle预防alert日志过大的脚本 参考:https://blog.csdn.net/jc_benben/article/details/88798523 在原文思路的基础上,做了一些修正,实测 ...

  9. JS Leetcode 33. 搜索旋转排序数组题解,图解旋转数组中的二分法

    壹 ❀ 引 本来今天(2021.4.7)的每日一题是81. 搜索旋转排序数组 II,但今天工作很忙,下班人基本累个半死,题目别说按照二分法的思路做不出来,连题解看了会都没法沉下心去看,不过得到的信息是 ...

  10. CF1823D Unique Palindromes

    题目链接 题解 知识点:构造. 首先反证法容易证明一个结论:每次增加一个字符,本质不同的回文子串至多增加一个. 那么无解的条件就是,\(c_i - c_{i-1} > x_i -x_{i-1}\ ...