Golang入门学习(7)

Go的第七课——函数

函数

函数简介

函数是 golang 中的一级公民,我们把所有的功能单元都定义在函数中,可以重复使用。函数包含函数的名称、参数列表和返回值类型,这些构成了函数的签名(signature),有点像 C++ 的名称粉碎机制。

函数的特性

  1. go语言中有3种函数:普通函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)。receiver
  2. go语言中不允许函数重载(overload),也就是说不允许函数同名。
  3. go语言中的函数不能嵌套函数,但可以嵌套匿名函数。
  4. 函数是一个值,可以将函数赋值给变量,使得这个变量也成为函数。
  5. 函数可以作为参数传递给另一个函数。I函数的返回值可以是一个函数。
  6. 函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。
  7. 函数参数可以没有名称。

函数定义

根据如下格式定义

1
2
3
func function_name([parameter_list]) [return_list]{
//main logic
}

最简单的一个加法函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func sum(a int, b int) int {
return a + b
}

func main() {
r := sum(1, 2)
fmt.Println(r)
}
/*
3
*/

返回值

一个函数可以有多个返回值,在返回的时候我们把返回的值用逗号隔开,接收的时候变量也使用逗号隔开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "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)
}
/*
3 1
*/

参数

参数这里有点小意思,它可以支持可变长度的参数,如果我们有需要可以用这种写法:

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 main

import "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)
}
/*
36
*/

参数一般是传形参,在调用的时候会拷贝一份数据进去,但是如果传的是指针,那么修改指针所指向的值有可能导致原值发生变化。需要注意的是,数组,切片,channelmap 这些数据类型传递的时候本来就是以指针的形式传递,修改它们内部的值有可能导致原值发生变化。

不过看 B 站上有一条弹幕说是

go 的数组不是指针类型,修改它不会导致原值发生变化。

为此我专门测试了以下,结果果真如此。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "fmt"

func sum(a [5]int) {
a[0] = 1000
}

func main() {
var a [5]int
sum(a)
fmt.Println(a[0])
}
/*
0
*/

而如果是切片的话就会改变原值,不过我想数组传参需要指定长度的参数也太苛刻了,一般都是用切片吧,所以叫这个真也没必要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "fmt"

func sum(a []int) {
a[0] = 1000
}

func main() {
var a = []int{0, 0}
sum(a)
fmt.Println(a[0])
}
/*
1000
*/

函数类型与函数变量

可以使用 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 main

import "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)
}
/*
1
2
*/

在这里我们声明的 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 main

import "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")
}
/*
Hello,xia0ji233
Good bye,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 main

import "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)
}
/*
10
6
16
4
*/

匿名函数

go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一下简单功能调用。

所谓匿名函数就是,没有名称的函数。

语法格式如下:

1
2
3
func (arglist)(return_list){
//main_logic
}

匿名函数的特点就是没有函数名,不能通过函数名调用,只依赖于创建时候返回的一个函数指针,也就是赋值给函数变量的值,一但值丢失那么就无法通过任何形式去调用了,作用域不限,只要指针给出去了可以在任何地方调用。

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 main

import "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)
}
/*
2
9
*/
文章目录
  1. 1. 函数
    1. 1.1. 函数简介
    2. 1.2. 函数的特性
    3. 1.3. 函数定义
    4. 1.4. 返回值
    5. 1.5. 参数
    6. 1.6. 函数类型与函数变量
    7. 1.7. 高阶函数
      1. 1.7.1. 函数作为参数
      2. 1.7.2. 函数作为返回值
    8. 1.8. 匿名函数
|