04-函数

函数的声明

注意:定义函数的时候,‘{’ 必须和函数名在同一行,不能另起一行。

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
package main

import "fmt"

func main() {

println("foo1:", foo1(1, 3))

foo2a, foo2b := foo2(1, false)
println("foo2:", foo2a, foo2b)

foo3ra, foo3rb := foo3("666", "777")
println("foo3:", foo3ra, foo3rb)

foo4rx, foo4ry, foo4ra, foo4rb := foo4("hello", "function", 1, 2)
println("foo4:", foo4rx, foo4ry, foo4ra, foo4rb)
}

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

// 多个返回值,返回值形参匿名
func foo2(a int, b bool) (bool, int) {
return !b, a + 1
}

// 多个返回值,返回值形参有名称
func foo3(a string, b string) (ra int, rb int) {
fmt.Println("---- foo3 ----")
fmt.Println("a = ", a)
fmt.Println("b = ", b)

//ra rb 属于foo3的形参,初始化默认的值为0
//ra rb 作用域空间 是foo3 整个函数体的{}空间
fmt.Println("ra = ", ra)
fmt.Println("rb = ", rb)

//给有名称的返回值变量赋值
ra = 2333
rb = 3332

return
}

// 形参类型相同时,可在最后声明类型
func foo4(x, y string, a, b int) (r4x, r4y string, r4a, r4b int) {
r4x, r4y, r4a, r4b = x, y, a, b
return
}

init 函数与 import

首先我们看一个例子:init函数:

init 函数可在 package main 中,可在其他 package 中,可在同一个 package 中出现多次。

main函数

main 函数只能在 package main 中。

执行顺序

golang 里面有两个保留的函数:init 函数(能够应用于所有的package)和 main函数(只能应用于package main)。这两个函数在定义时不能有任何的参数和返回值。

虽然一个 package 里面可以写任意多个 init 函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个 package 中每个文件只写一个 init 函数。

go 程序会自动调用 init() 和 main(),所以你不需要在任何地方调用这两个函数。每个 package 中的 init 函数都是可选的,但 package main 就必须包含一个 main 函数。

程序的初始化和执行都起始于 main 包。

如果 main 包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到fmt包,但它只会被导入一次,因为没有必要导入多次)。

当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行init函数(如果有的话),依次类推。

等所有被导入的包都加载完毕了,就会开始对main包中的包级常量和变量进行初始化,然后执行main包中的init函数(如果存在的话),最后执行main函数。下图详细地解释了整个执行过程:

31-init.png

首先我们看一个例子:

代码结构:

32-init.png

Lib1.go

1
2
3
4
5
6
7
package InitLib1

import "fmt"

func init() {
fmt.Println("lib1")
}

Lib2.go

1
2
3
4
5
6
7
package InitLib2

import "fmt"

func init() {
fmt.Println("lib2")
}

main.go

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

import (
"fmt"
_ "GolangTraining/InitLib1"
_ "GolangTraining/InitLib2"
)

func init() {
fmt.Println("libmain init")
}

func main() {
fmt.Println("libmian main")
}

代码很简单,只是一些简单的输出

1
2
3
4
lib1
lib2
libmain init
libmian main

输出的顺序与我们上面图给出的顺序是一致的

那我们现在就改动一个地方,Lib1包导入Lib2,main包不管

1
2
3
4
5
6
7
8
9
10
package InitLib1

import (
"fmt"
_ "GolangTraining/InitLib2"
)

func init() {
fmt.Println("lib1")
}

输出:

1
2
3
4
lib2
lib1
libmain init
libmian main

main包以及Lib1包都导入了Lib2,但是只出现一次,并且最先输出,

说明如果一个包会被多个包同时导入,那么它只会被导入一次,而先输出lib2是因为main包中导入Lib1时,Lib1又导入了Lib2,会首先初始化Lib2包的东西

函数参数

函数如果使用参数,该变量可称为函数的形参。

形参就像定义在函数体内的局部变量。

调用函数,可以通过两种方式来传递参数:

值传递

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

以下定义了 swap() 函数:

1
2
3
4
5
6
7
8
9
10
11
12
/* 定义相互交换值的函数 */
func swap(x, y int) int {
var temp int


temp = x /* 保存 x 的值 */
x = y /* 将 y 值赋给 x */
y = temp /* 将 temp 值赋给 y*/


return temp;
}

接下来,让我们使用值传递来调用 swap() 函数:

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
package main


import "fmt"


func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200


fmt.Printf("交换前 a 的值为 : %d\n", a )
fmt.Printf("交换前 b 的值为 : %d\n", b )


/* 通过调用函数来交换值 */
swap(a, b)


fmt.Printf("交换后 a 的值 : %d\n", a )
fmt.Printf("交换后 b 的值 : %d\n", b )
}


/* 定义相互交换值的函数 */
func swap(x, y int) int {
var temp int


temp = x /* 保存 x 的值 */
x = y /* 将 y 值赋给 x */
y = temp /* 将 temp 值赋给 y*/


return temp;
}

以下代码执行结果为:

1
2
3
4
交换前 a 的值为 : 100
交换前 b 的值为 : 200
交换后 a 的值 : 100
交换后 b 的值 : 200

引用传递(指针传递)

指针

Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。接下来让我们来一步步学习 Go 语言指针。

我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

以下实例演示了变量在内存中地址:

1
2
3
4
5
6
7
8
9
10
package main


import "fmt"


func main() {
var a int = 10
fmt.Printf("变量的地址: %x\n", &a )
}

执行以上代码输出结果为:

1
变量的地址: 20818a220

现在我们已经了解了什么是内存地址和如何去访问它。接下来我们将具体介绍指针。

引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

引用传递指针参数传递到函数内,以下是交换函数 swap() 使用了引用传递:

1
2
3
4
5
6
7
/* 定义交换值函数*/
func swap(x *int, y *int) {
var temp int
temp = *x /* 保持 x 地址上的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y */
}

以下我们通过使用引用传递来调用 swap() 函数:

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
package main


import "fmt"


func main() {
/* 定义局部变量 */
var a int = 100
var b int= 200


fmt.Printf("交换前,a 的值 : %d\n", a )
fmt.Printf("交换前,b 的值 : %d\n", b )


/* 调用 swap() 函数
* &a 指向 a 指针,a 变量的地址
* &b 指向 b 指针,b 变量的地址
*/
swap(&a, &b)


fmt.Printf("交换后,a 的值 : %d\n", a )
fmt.Printf("交换后,b 的值 : %d\n", b )
}


func swap(x *int, y *int) {
var temp int
temp = *x /* 保存 x 地址上的值 */
*x = *y /* 将 y 值赋给 x */
*y = temp /* 将 temp 值赋给 y */
}

以上代码执行结果为:

1
2
3
4
交换前,a 的值 : 100
交换前,b 的值 : 200
交换后,a 的值 : 200
交换后,b 的值 : 100

04-函数
https://flepeng.github.io/021-Go-01-course-04-函数/
作者
Lepeng
发布于
2024年11月1日
许可协议