函数(function)
函数是基本的代码块
函数编写的顺序无关紧要;鉴于可读性的需求,最好把 main()
函数写在文件的前面
DRY 原则:不要重复你自己(Don’t Repeat Yourself)
三种类型:
- 普通的带有名字的函数
- 匿名函数或者 lambda 函数
- 方法(Methods)
除了 main ()、init () 函数外,其它所有类型的函数都可以有参数与返回值
函数签名:函数参数、返回值以及它们的类型
Go 语言不支持函数重载
函数也可以以申明的方式被使用,作为一个函数类型
type binOp func(int, int) int
函数值(functions value)之间可以相互比较:如果它们引用相同的函数或者都是 nil 的话,则认为它们是相同的函数
不能在其它函数里面声明(不能嵌套),但同时支持匿名函数
目前(go1.17.2)不支持泛型(可通过空接口或类型选择 type switch 实现,会使代码可读性差、性能弱,不推荐)
参数与返回值
可以返回零个或多个值(我们通常把返回多个值称为返回一组值)
任何一个有返回值(单个或多个)的函数都必须以 return
或 panic
结尾
可以定义没有形参名的函数,只有相应的形参类型
func f(int, int, float64)
没有参数的函数通常被称为 niladic 函数(niladic function),就像 main.main()
值传递 & 引用传递
Go 默认使用按值传递来传递参数,即传递参数的副本
几乎在任何情况下,传递指针(一个 32 位或者 64 位的值)的消耗都比传递副本来得少
命名的返回值
// 非命名返回值
func name(a, b type) (type, type) {}
// 命名返回值
// 返回值在函数调用时就被赋予一个类型零值,返回时直接 return 即可
func name(a, b type) (m type, n type) {}
尽量使用命名返回值:会使代码更清晰、更简短,同时更加容易读懂
空白符
_
用来匹配一些不需要的值,然后丢弃掉
改变外部变量
传递指针给函数不但可以节省内存,且赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用 return
返回
传递变长参数
如果函数的最后一个参数是采用 ...type
的形式,那么这个函数就可以处理一个变长的参数(长度可以为 0)
func myFunc(a, b, arg ...type) {}
如果参数被存储在一个 slice 类型的变量 slice
中,则可以通过 slice...
的形式来传递参数调用变参函数
defer 和追踪
defer 允许我们推迟到函数返回之前(或任意位置执行 return
语句之后)一刻才执行某个语句或函数
类似于Java
中的finally
,可用于释放分配的资源
defer func(){
// todo
}
可以接收参数
多个 defer 被注册时,逆序执行(类似栈,后进先出)
使用 defer 语句实现代码追踪
可参考GoFirst
内置函数
new
和make
均是用于分配内存:new
用于值类型和用户定义的类型,如自定义结构,make
用于内置引用类型(切片、map 和管道)
new(T)
分配类型 T 的零值并返回其地址,即指向类型 T 的指针
(可用于基本类型;是一个函数)
make(T)
返回类型 T初始化
后的值
闭包函数
闭包函数保存并积累其中的变量的值,不管外部函数退出与否,它都能够继续操作外部函数中的局部变量
func main() {
var f = Adder()
fmt.Print(f(1), " - ")
fmt.Print(f(20), " - ")
fmt.Print(f(300))
}
func Adder() func(int) int {
// x 的值会被保留下来
var x int
return func(delta int) int {
x += delta
return x
}
}
// 1 - 21 - 321