go函数的特效
1:Go中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。
2:Go编译时不在乎函数的定义位置,但建议init()定义在最前面(如果有的话),main函数定义在init()之后,然后再根据函数名的字母顺序或者根据调用顺序放置各函数的位置。
3:函数的参数、返回值以及它们的类型,结合起来成为函数的签名(signature)。
4:函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
5:由于引用类型(slice、map、interface、channel)自身就是指针,所以这些类型的值拷贝给函数参数,函数内部的参数仍然指向它们的底层数据结构。
6:函数参数可以没有名称,例如func myfunc(int,int)。
7:Go中的函数可以作为一种type类型,例如type myfunc func(int,int) int。
实际上,在Go中,函数本身就是一种类型,它的signature就是所谓的type,例如func(int,int) int。所以,当函数ab()赋值给一个变量ref_ab时ref_ab := ab,不能再将其它函数类型的函数cd()赋值给变量ref_ab。
8:Go中不允许函数重载(overload),也就是说不允许函数同名。
9:Go中的函数不能嵌套函数,但可以嵌套匿名函数。
10:Go实现了一级函数(first-class functions),Go中的函数是高阶函数(high-order functions)。这意味着:
函数是一个值,可以将函数赋值给变量,使得这个变量也成为函数
函数可以作为参数传递给另一个函数
函数的返回值可以是一个函数
这些特性使得函数变得无比的灵活,例如回调函数、闭包等等功能都依赖于这些特性。
11:Go中的函数不支持泛型(目前不支持),但如果需要泛型的情况,大多数时候都可以通过接口、type switch、reflection的方式来解决。但使用这些技术使得代码变得更复杂,性能更低。
参数和返回值
函数可以有0或多个参数,0或多个返回值,参数和返回值都需要指定数据类型,返回值通过return关键字来指定。
return可以有参数,也可以没有参数,这些返回值可以有名称,也可以没有名称。Go中的函数可以有多个返回值。
- (1).当返回值有多个时,这些返回值必须使用括号包围,逗号分隔
- (2).return关键字中指定了参数时,返回值可以不用名称。如果return省略参数,则返回值部分必须带名称
- (3).当返回值有名称时,必须使用括号包围,逗号分隔,即使只有一个返回值
- (4).但即使返回值命名了,return中也可以强制指定其它返回值的名称,也就是说return的优先级更高
- (5).命名的返回值是预先声明好的,在函数内部可以直接使用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义
- (6).return中可以有表达式,但不能出现赋值表达式,这和其它语言可能有所不同。例如
return a+b
是正确的,但return c=a+b
是错误的
多返回值的应用场景:
1:Go中经常会使用其中一个返回值作为函数是否执行成功、是否有错误信息的判断条件。例如return value,exists、return value,ok、return value,err等。
2:返回多个值,有些没用要丢掉,解决方案 _ 表示丢掉的值
例如
func func_a() (a,b int){
return
}
func main() {
a,_ := func_a()
}
3:变长参数
函数参数太多,希望把这些多余的赋值给一个变量,使用 ... 的形式 例如:
func myfunc(a,b int,args...int) int {}
相当于在函数内部弄的一个slice: var args = []int{}
如果参数类型太多,可以把参数放在切片里面,然后传递给函数,调用当时 slice... 例如:
func main() {
s1 := []int{30,40,50,60,70}
fmt.Println(min(10,20,s1...))
}
func type
可以将func作为一种type,以后可以直接使用这个type来定义函数。也就是用type定义函数,例如:
package main
import "fmt"
type add func(a,b int) int
func main() {
var a add = func(a,b int) int{
return a+b
}
s := a(3,5)
fmt.Println(s)
}
其他:
new适用于为值类(value type)的数据类型(如array,int等)和struct类型的对象分配内存并初始化,并返回它们的指针给变量。如v := new(int)
make适用于为内置的引用类的类型(如slice、map、channel等)分配内存并初始化底层数据结构,并返回它们的指针给变量,同时可能会做一些额外的操作
new 和 make 都是为了给变量初始化并且分配内存,不同点在于偏向的对象不一样,
new 偏向于值类型变量
make服务于引用类型的变量