Go的第七课——函数
函数 函数简介 函数是 golang 中的一级公民 ,我们把所有的功能单元都定义在函数中,可以重复使用。函数包含函数的名称、参数列表和返回值类型,这些构成了函数的签名(signature),有点像 C++ 的名称粉碎机制。
函数的特性
go语言中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。receiver
go语言中不允许函数重载(overload),也就是说不允许函数同名。
go语言中的函数不能嵌套函数,但可以嵌套匿名函数。
函数是一个值,可以将函数赋值给变量,使得这个变量也成为函数。
函数可以作为参数传递给另一个函数。I函数的返回值可以是一个函数。
函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
函数参数可以没有名称。
函数定义 根据如下格式定义
1 2 3 func function_name ([parameter_list]) [return_list]{ }
最简单的一个加法函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport "fmt" func sum (a int , b int ) int { return a + b } func main () { r := sum(1 , 2 ) fmt.Println(r) }
返回值 一个函数可以有多个返回值,在返回的时候我们把返回的值用逗号隔开,接收的时候变量也使用逗号隔开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport "fmt" func sum (a int , b int ) (int , int ) { return a + b, a - b } func main () { l, r := sum(2 , 1 ) fmt.Println(l, r) }
参数 参数这里有点小意思,它可以支持可变长度的参数,如果我们有需要可以用这种写法:
1 func function_name (arg1 type1,arg2 type2,ARGS...type ) (return_list)
这个意思就是至少要传两个参数,其余参数会进入 ARGS 切片中,我们在里面要使用需要对 ARGS 进行操作,并且这个可变参数的写法必须要放在最后一个参数。
前面还说过,在调用的时候我们也可以使用 ...
这个意思就是把一个切片的值分别当作函数的参数传递进去。
比如切片 a={1,2,3,4,5}
那么我调用 add(a...)
意思就是调用 add(1,2,3,4,5)
,这个写法还是挺方便的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport "fmt" func sum (ARGS ...int ) int { val := 0 for _, v := range ARGS { val += v } return val } func main () { var a = []int {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } val := sum(a...) fmt.Println(val) }
参数一般是传形参,在调用的时候会拷贝一份数据进去,但是如果传的是指针,那么修改指针所指向的值有可能导致原值发生变化。需要注意的是,数组,切片,channel
,map
这些数据类型传递的时候本来就是以指针的形式传递,修改它们内部的值有可能导致原值发生变化。
不过看 B 站上有一条弹幕说是
go 的数组不是指针类型,修改它不会导致原值发生变化。
为此我专门测试了以下,结果果真如此。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport "fmt" func sum (a [5]int ) { a[0 ] = 1000 } func main () { var a [5 ]int sum(a) fmt.Println(a[0 ]) }
而如果是切片的话就会改变原值,不过我想数组传参需要指定长度的参数也太苛刻了,一般都是用切片吧,所以叫这个真也没必要。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport "fmt" func sum (a []int ) { a[0 ] = 1000 } func main () { var a = []int {0 , 0 } sum(a) fmt.Println(a[0 ]) }
函数类型与函数变量 可以使用 type
关键字来定义一个函数类型,语法格式如下:
1 type identifier func (arg_list) (return_list)
用 C++ 的话说是定义了一个 identifier 类型,是一个函数指针类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" type f func (int ) int func fun (a int ) int { return a } func fun1 (b int ) int { return b + 1 } func main () { var ptr f ptr = fun s := ptr(1 ) fmt.Println(s) ptr = fun1 s = ptr(1 ) fmt.Println(s) }
在这里我们声明的 ptr 变量就属于 f 类的函数变量。
高阶函数 go语言的函数,可以作为函数的参数,传递给另外一个函数,作为另外一个函数的返回值返回。
函数作为参数 就是把参数类型定义为函数类型,然后在内部调用即可,跟函数指针差不多的用法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" type pfunc func (string ) func say_hello (name string ) { fmt.Printf("Hello,%s\n" , name) } func say_goodby (name string ) { fmt.Printf("Good bye,%s\n" , name) } func call_function (f func (string ) , arg string ) { f(arg) } func main () { var ptr pfunc ptr = say_hello call_function(ptr, "xia0ji233" ) ptr = say_goodby call_function(ptr, "xia0ji233" ) }
函数作为返回值 就是返回一个函数指针罢了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package mainimport "fmt" type pfunc func (int , int ) int func add (a int , b int ) int { return a + b } func sub (a int , b int ) int { return a - b } func mul (a int , b int ) int { return a * b } func div (a int , b int ) int { return a / b } func cal (op string ) pfunc { switch op { case "+" : return add case "-" : return sub case "*" : return mul case "/" : return div default : return nil } } func main () { var v int v = cal("+" )(8 , 2 ) fmt.Println(v) v = cal("-" )(8 , 2 ) fmt.Println(v) v = cal("*" )(8 , 2 ) fmt.Println(v) v = cal("/" )(8 , 2 ) fmt.Println(v) }
匿名函数 go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一下简单功能调用。
所谓匿名函数就是,没有名称的函数。
语法格式如下:
1 2 3 func (arglist) (return_list){ }
匿名函数的特点就是没有函数名,不能通过函数名调用,只依赖于创建时候返回的一个函数指针,也就是赋值给函数变量的值,一但值丢失那么就无法通过任何形式去调用了,作用域不限,只要指针给出去了可以在任何地方调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" type pfunc func (int , int ) int func call_function (f func (int , int ) int , a int , b int ) int { return f(a, b) } func main () { var v int max := func (a int , b int ) int { if a > b { return a } return b } v = max(1 , 2 ) fmt.Println(v) v = call_function(max, 8 , 9 ) fmt.Println(v) }