学到什么
- 如何调用函数?
- 如何构造函数?
- 函数如何返回多个值?
- 如何构造匿名函数?
- 如何传递函数?
- 内置函数有哪些?
介绍
函数是基本的代码块,它负责将一个复杂问题分解为不同的函数提供调用与复用。
编写函数时,无需关注顺序,因为它 Go 语言是编译型的。
在 Go 语言中总共分 3 中函数格式:
- 基本格式:有命名的函数,直接调用完事。
- 匿名函数:没有名字的函数。
- 结构体携带的函数:也可以称之为方法,后续结构体再展开讲解。
基本格式
func Fun1(arg1 T, arg2 T) T { ... return r1 }
Fun1
为自定义的函数名称。
arg1
和arg2
为自定义参数名称,声明了两个参数,可以再增加。
T
代表 Go 语言中的任意类型,使用时替换成 int、string、slice 等等类型。
- 小括号后紧跟函数返回值类型。
return
为函数返回的关键字,携带要返回的值,函数之后的逻辑将不会执行。
- 函数体的第一个花括号必须紧跟在函数后。
举例:
// 计算两个数之和并且返回 func AddNum(n1 int, n2 int) int { return n1 + n2 }
函数也可以没有返回值,这个时候就无需
return
关键字,例如:main() 、init() 内置函数当函数体内出现了
panic
函数,用于抛出异常,这时如果定义了返回类型, return
关键字就可以选择省略。返回多个值
Go 语言函数中有个特点,可以多个值返回。在声明返回值类型时,可以不指定名称,也可以指定名称,啥意思呢,往下看。
1. 无名称
func Fun1(arg1 T, arg2 T) (T, T) { ... return r1, r2 }
和“基本格式”的不同点:
- 当需要返回至少两个值时,返回类型需要用小括号包裹,以逗号分隔。
- 使用
return
携带多个返回值。
2. 有名称
func Fun1(arg1 T, arg2 T) (n1 T, n2 T) { ... return }
- 返回值类型指定了名称后,在
return
返回时,可以不带值,当然也可以都带上。
- 当有了名称,即使是 1 个返回类型,也需要用小括号包裹。
为什么有了名称就
return
不用携带值呢?因为相当于在返回时,初始化好了返回值,例如上面的格式中
n1
和 n2
就是初始化的两个变量,在函数运算中,只要将返回结果存入 n1
和 n2
中,不存就按照初始化返回,当然也可以 return
携带值。函数调用
构造好一个函数后,如何调用,格式如下:
r1, r2 := Fun1(param1, param2)
调用时传递了两个参数,返回时接受两个返回值。
如果接受多个值时,某个值我不想使用时,是不能搁置在那的,不然编译器会报错,需要使用下划线 "_" 替代,表示我不用。
r1, _ := Fun1(param1, param2)
匿名函数
匿名函数就是在构造函数时,函数没有名称,想调用时,需要把匿名函数赋值给一个变量,或者在构造时直接调用。
1. 赋值给变量
fun1 := func (arg1 T, arg2 T) T { ... return r1 }
赋值后,
fun1
就是一个函数类型的变量, 调用格式:fun1(param1, param2)
。2. 构造时调用
func (arg1 T, arg2 T) T { ... return r1 }(param1, param2)
在构造函数时,花括号后紧跟参数
(param1, param2)
传递,不需要赋值给一个变量,直接构造后马上调用。传递函数
在 Go 语言中,函数是“一等公民”,它和 int 、string 等等,都是一个级别。可以存储到一个变量中进行传递。
举例:
// function/deliver.go package main // callback 是一个函数类型参数 func Calc(callback func(n1 int, n2 int) int) int { x, y := 3, 4 return callback(x, y) } // 计算两数之积 func Mul(n1 int, n2 int) int { return n1 * n2 } func main() { // 第一个:传递一个匿名函数 Calc(func(n1 int, n2 int) int { return n1 + n2 }) // 第二个:传递一个定义好的函数 Calc(Mul) }
分别演示了两种函数的传递方式,第一个匿名函数计算两数之和,第二个用定义好的函数计算两数之积。当然传递函数不止是通过参数,也可以是函数返回值、切片元素保存、map值保存等等。
声明函数类型
声明函数类型,意思就是可以自定义一个函数类型,给这个函数取一个别名,像例如
int
一样很方便的去声明变量或者参数类型。type CallbackFunc func(n1 int, n2 int) int
现在自定义了一个名为
CallbackFunc
的函数类型,下来看如何使用:func Calc(callback CallbackFunc) int { ... }
Calc
函数有一个函数参数,这个参数的类型名称为 CallbackFunc
。函数参数
1. 参数类型省略
在声明函数参数时,有时候会遇到连续声明多个相同类型,这个时候,就可以只保留一个类型名称。
// 没精简的 func Fun1(arg1 string, arg2 int, arg3 int) // 精简后 func Fun1(arg1 string, arg2, arg3 int)
精简后,
arg2
参数后省略了 int,这样就和它后面的参数类型一致。2. 值传递与引用传递
我们先定下参数称呼,函数调用时传递的参数称为实参,构造函数时的参数称为形参。
在 Go 语言中,切片(slice)、map、接口(interface)、通道(channel)这样的引用类型都是默认使用引用传递,在函数内修改形参是会改变实参的值。
对于切片,有种情况会打破引用传递这个规律,具体可以看看 《内置结合 - 切片》这篇文章。
对于其它剩下的类型,默认都是值传递,函数接收到的形参只是副本,函数内对形参的更改是不会影响到实参的。
如果希望更改实参的值,可以传递指针,在实参前增加“&”符号,表示取实参的地址,例如:
Fun1(¶m)
。3. 变长参数
当构造函数时,函数的最后一个参数是
...T
形式时,称为可变参数,它可以接受至少 0 个数据。// 一个固定参数,一个可变参数 // nums 实际是一个切片 func Func1(str string, nums ...int) { ... }
调用例子如下:
// 没传递可变参数 Func1("miao") // 给可变参数传递不同数量的值 Func1("miao", 1) Func1("miao", 1, 2)
当把一个切片类型传递给可变参数时,在切片后跟着
...
三个点,传递给可变参数,表示将切片元素展开。nums := []int{1, 2, 3} Func1("miao", nums...)
内置函数
在 Go 语言中,有一些函数无需导入任何包就可以使用,下来对这些包简要说明一下。
总共 15 个内置函数,如下:
- make:为切片,map、通道类型分配内存并初始化对象。
- len:计算数组、切片、map、通道的长度。
- cap:计算数组、切片、通道的容量。
- delete:删除map中对应的键值对。
- append:将数据添加到切片的末尾。
- copy:将原切片的数据复制到新切片中。
- new:为切片、map、通道类型以外的类型分配内存并初始化对象,返回的类型为指针。
- complex:生成一个复数。
- real:获取复数的实部。
- imag:获取复数的虚部
- print:将信息打印到标准输出,没有换行。
- println:将信息打印到标准输出并换行。
- close:关闭通道。
- panic:触发程序异常。
- recover:捕捉 panic 的异常信息。
总结
本篇我对 Go 语言中的函数进行了系统的讲解,也列举了 15 个内置函数。对于内置函数的使用,有的在前面文章使用过,有的还没有,先做一个整体的了解,等到了用的时候再详查。