go-doc-函数

函数

  • 基本语法
1
2
3
4
func 函数名 (形参列表) (返回值列表) {
执行语句 ...
return 返回值列表
}

函数要点

  1. Go函数支持返回多个值
  2. 如果返回多个值时,在接收时,希望忽略某个返回值,则使用 _ 符号表示占位忽略
  3. 如果返回值只有一个,可以不写()
  4. Go函数不支持重载
  5. Go中函数也是一种数据类型,可以赋值给变量,则该变量就是函数类型的变量,通过该变量可以对函数调用
  6. Go支持对函数返回值命名,这样好处是返回值顺序不怕错乱
  7. Go支持可变参数,可变参数一定要放在形参列表最后
  8. 函数参数类型省略的形参,会以最靠后一个有定义类型的形参类型统一
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
package main 

import (
"fmt"
)

// 接收2个参数没有返回值的函数
func func1(i int, j int) {
fmt.Println("func1.....", i, j)
}

// 接收2个参数返回1个值的函数
func func2(i int, j int) int {
fmt.Println("func1.....", i, j)

return i
}

// 接收2个参数返回2个值的函数
func func3(i int, j int) (int, int) {
fmt.Println("func1.....", i, j)

return i, j
}

// 接收一个函数类型参数的函数
func func4(fun func(int , int) (int, int), i int, j int) (int, int) {
return fun(i, j)
}

func main() {
func1(1, 2);
var f21 = func2(1, 2)
var f31, _ = func3(1, 2)
var _, f32 = func3(1, 2)

var fun1 = func3
func4(fun1, 1, 2)

fmt.Println(f21, f31, f32)
fmt.Printf("%T \n", fun1)
}

init函数

每个源文件都可以包含一个init函数

init函数要点

  1. init函数会在main函数之前被执行
  2. 如果源文件由全局变量,则顺序是全局变量先定义,然后到init在到main函数
1
2
3
4
5
6
7
8
9
10
11
12
13
package main 

import (
"fmt"
)

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

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

匿名函数

如果我们某个函数只希望使用一次,可以考虑使用匿名函数,当然,匿名函数也可以被多次调用

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

import (
"fmt"
)

// 全局匿名函数定义
var funSum2 = func(i int, j int) int {
return i + j
}

func main() {
// 局部匿名函数定义
var funSum = func(i int, j int) int {
return i + j
}

var sum1 = funSum(1, 2)
var sum2 = funSum2(2, 3)

fmt.Println(sum1, sum2)
}

闭包

闭包就是一个函数和与其相关的引用环境组合成一个整体

可以理解为,闭包是类

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

import (
"fmt"
)

// 闭包函数
func addUpper() func(int) int {
var n int = 10
return func(x int) int {
// 匿名函数和n形成一个整体,构成闭包
n = n + x
return n
}
}

func main() {
var up = addUpper()

fmt.Println(up(1)) // 11
fmt.Println(up(2)) // 13
fmt.Println(up(3)) // 16
}

defer

为了在函数执行完毕后,及时的释放资源,Go提供了defer(延时机制)

defer要点

  1. 当执行到defer时,defer修饰的语句先不执行,会被压入独立的栈中
  2. 当函数执行完毕后,在从defer栈,按照先入后出的方式出栈,执行
  3. 在defer将放入栈时,也会将相关的值拷贝同时入栈

函数参数的传递方式

参数传递方式

  1. 值传递
  2. 引用传递

不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低

函数类型定义

为了简化数据类型定义,Go支持自定义数据类型

package main 

import (
    "fmt"
)

func func2(i int, j int) int {
    fmt.Println("func1.....", i, j)

    return i
}

// 全局定义函数类型
type myFunc2 func(int, int) int

func main() {
    // 局部内定义一个int类型
    type int2 int
    var num1 int2 = 30
    var num2 int = int(num1)

    fmt.Println(num1, num2)

    var fun2 = func2
    var fun3 myFunc2 = func2

    fun2(1, 2)
    fun3(1, 3)
}