Let's Go 3

Go 函数

函数是基本的代码块,用于执行一个任务。

Go 函数定义格式如下:

1
2
3
func function_name( [parameter list] ) [return_types] {
函数体
}

函数定义解析

  • func:函数由 func 开始声明

  • function_name:函数名称,函数名和参数列表一起构成了函数签名。

  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。

  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,则 return_types 不是必须的。

  • 函数体:函数定义的代码集合。

函数调用

定义函数只是指定了函数的形式,需要调用该函数才能执行指定的代码块。

函数调用就是执行函数定义的代码块。

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

import "fmt"

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

/* 调用函数并返回最大值 */
ret = max(a, b)

fmt.Printf( "最大值是 : %d\n", ret )
}

/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int

if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}

函数返回多个值

Go 函数支持返回多个返回值,函数定义时可以定义返回值的类型和个数。

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

import "fmt"

func swap(x, y string) (string, string) {
return y, x
}

func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}

函数作为值、类型

在 Go 语言中,函数也是一种变量,我们可以通过 type 来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。

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

import "fmt"

type cb func(int) int

func main() {
var c cb
c = func(x int) int {
return x * x
}
fmt.Println(c(10))
}

形参、实参、可变参数与传值、传引用

形参:形式参数,定义函数时,用于接收外部传入的数据。

实参:实际参数,调用函数时,传递给形参的数据。

可变参数:可变参数是指函数的参数数量不固定,可变参数需要放在形参最后。

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

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

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
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
}

分析:在上面的程序中,我们定义了一个 swap() 函数,用于交换传入的两个整型参数的值。

在 main() 函数中,我们声明了两个局部变量 a 和 b,并赋值为 100 和 200。

在调用 swap() 函数时,我们传递 a 和 b 的值作为参数,但实际上 swap() 函数接收到的是 a 和 b 的副本,swap() 函数交换的是这两个副本的值,并没有改变 a 和 b 的值。

Go 函数方法

Go 语言中同时有函数和方法。

一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。

所有给定类型的方法属于该类型的方法集。

语法格式如下:

1
2
3
func (variable_name variable_data_type) function_name() [return_type]{
/* 函数体*/
}
  • variable_name:变量名,实例中的接受者。

  • variable_data_type:变量类型,实例中的接受者类型。

  • function_name:函数名,实例中的函数名。

  • return_type:返回类型,实例中的返回类型。

函数方法实例

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

import "fmt"

type Circle struct {
radius float64
}

func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("圆的面积 = ", c1.getArea())
}

//该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
//c.radius 即为 Circle 类型对象中的属性
return 3.14 * c.radius * c.radius
}

Go 递归函数

Go 语言支持递归,即在函数定义中调用自己。

但是在使用递归时,程序员需要注意定义一个退出条件,否则递归将陷入无限循环中。

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

import "fmt"

func Factorial(n uint64)(result uint64) {
if (n > 0) {
result = n * Factorial(n-1)
return result
}
return 1
}
func main() {
var i int = 15
fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}

defer 语句

Go 语言中的 defer 语句会将其后面跟随的语句进行延迟处理。

在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 定义的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
defer fmt.Println("world")

fmt.Println("hello")
}

闭包

闭包是匿名函数,可在动态编程中使用。

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

import "fmt"

func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}

func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()

/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())

/* 创建新的函数 nextNumber1,并查看结果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}

匿名函数推导式

匿名函数是指不需要定义函数名的一种函数实现方式。

匿名函数由一个不带函数名的函数声明和函数体组成。

匿名函数的优越性在于可以直接使用函数内的变量,不必申明。

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

import "fmt"

func main() {
/* 声明函数变量 */
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}

/* 使用函数 */
fmt.Println(getSquareRoot(9))
}

函数式编程

函数式编程是一种编程范式,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。

函数式编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。

函数式编程的主要思想是把运算过程尽量写成一系列嵌套的函数调用。

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

import "fmt"

func main() {
/* 声明函数变量 */
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}

/* 使用函数 */
fmt.Println(getSquareRoot(9))
}