Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

My Blog

从此烟雨落金城,一人撑伞两人行。

第六章:函数

简介

函数是基本的代码块。函数编写的顺序是无关紧要的,最好把 main() 函数写在文件的前面。

简单的 return 语句也可以用来结束 for 死循环,或者结束一个协程(goroutine)。

Go里面的函数:

  • 普通函数
  • 匿名函数
  • 方法

除了main()、init()函数外,其它所有类型的函数都可以有参数与返回值。

函数参数、返回值以及它们的类型被统称为函数签名。

函数是一等值(first-class value):它们可以赋值给变量,就像 add := binOp 一样。

函数不能在其它函数里面声明(不能嵌套),不过我们可以通过使用匿名函数

函数参数与返回值

函数定义时,它的形参一般是有名字的,不过我们也可以定义没有形参名的函数,只有相应的形参类型,就像这样:func f(int, int, float64)

在函数调用时,像切片(slice)、字典(map)、接口(interface)、通道(channel)这样的引用类型都是默认使用引用传递(即使没有显式的指出指针)。

命名返回值

命名返回值作为结果形参(result parameters)被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的return语句。

1
2
3
4
5
6
func getX2AndX3_2(input int) (x2 int, x3 int) {
x2 = 2 * input
x3 = 3 * input
// return x2, x3
return
}

改变外部变量

传递指针给函数不但可以节省内存(因为没有复制变量的值),而且赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用 return 返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import (
"fmt"
)
// this function changes reply:
func Multiply(a, b int, reply *int) {
*reply = a * b
}
func main() {
n := 0
reply := &n
Multiply(10, 5, reply)
fmt.Println("Multiply:", *reply) // Multiply: 50
}

变长参数

函数的最后一个参数是采用 ...type 的形式,那么这个函数就可以处理一个变长的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import "fmt"
func main() {
x := min(1, 3, 2, 0)
fmt.Printf("The minimum is: %d\n", x)
slice := []int{7,9,3,5,1}
x = min(slice...)
fmt.Printf("The minimum in the slice is: %d", x)
}
func min(s ...int) int {
if len(s)==0 {
return 0
}
min := s[0]
for _, v := range s {
if v < min {
min = v
}
}
return min
}

变长参数的类型不相同

  1. 使用结构体

  2. 使用空接口

    使用默认的空接口 interface{},这样就可以接受任何类型的参数

new 和 make 均是用于分配内存:new 用于值类型和用户定义的类型,如自定义结构,make 用于内置引用类型(切片、map 和管道)。

new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针

make(T) 返回类型 T 的初始化之后的值,因此它比 new 进行更多的工作。

defer和追踪

关键字 defer 允许我们推迟到函数返回之前(或任意位置执行 return 语句之后)一刻才执行某个语句或函数。

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

func P(){
fmt.Print("P")
}

func main(){
fmt.Print("111")
defer P()
fmt.Print("222")
}

当有多个 defer 行为被注册时,它们会以逆序执行

1
2
3
4
5
6
7
8
9
10
11
12
package mian
import (
"file")
func main(){
//关闭文件
defer file.close()
//解锁
mu.Lock()
defer mu.Unlock()
//关闭数据库连接
defer disconnectFromDB()
}

函数作为参数

1
2
3
4
5
6
7
8
9
10
11
package main
import "fmt"
func add(i,j int) int {
return i+j
}
func b(c int, f func (i,j int) int ){
return f(c, 2)
}
func main(){
fmt.Print(b(1, add))
}

闭包

匿名函数的使用

1
2
3
4
5
6
7
8
9
10
package main
import "fmt"
func main (){
// 匿名函数 func(i, j int) int {return i+j}
// 将匿名函数赋值给变量 变量使用匿名函数
ter := func(i, j int) int {return i+j}
ter(2,3)
// 匿名函数直接的调用
func(a, b int) int {return a-b} (3, 2)
}

函数作为返回值

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

func add(j int) func (i int) int{
return func (i int) int{
return j +i
}
}

func main(){
add(12)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

func add() func(i int) int {
var x int
fmt.Printf("x: %v\n", x)
return func(i int) int {
x += i
return x
}
}
func main() {
f := add()
fmt.Printf("f(1): %v\n", f(1))
fmt.Printf("f(2): %v\n", f(20))

}

闭包函数保存并积累其中的变量的值,不管外部函数退出与否,它都能够继续操作外部函数中的局部变量。

计算函数的执行时间

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

import (
"fmt"
"time"
)

func add() {
for i := 0; i < 100; i++ {
fmt.Printf("i: %v\n", i)
}
}

func main() {
start := time.Now()
add()
end := time.Now()
fmt.Print(end.Sub(start))
}

评论