乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

    • Golang基础知识

      • 开发环境搭建
      • 常量与变量
      • 基本数据类型
      • 复合数据类型
      • 流程控制
      • 运算符
      • 位运算符详解
      • 指针
      • map
      • 函数
        • 函数的定义
        • 函数的调用
        • 函数的其他定义方式
          • 类型简写
          • 返回值变量省略
          • 可变参数
        • 函数的进阶
          • 变量的作用域
          • 全局变量
          • 局部变量
          • 函数类型与变量
          • 函数类型
          • 函数类型的变量
          • 高阶函数
          • 函数作为参数
          • 函数作为返回值
          • 匿名函数
          • 闭包
        • 内部函数
        • 递归函数
      • defer
      • 类型别名与自定义类型
      • 结构体
      • 接口
      • 包
      • 文件操作
      • 反射
      • 并发
      • socket网络编程
      • HTTP网络编程
      • 单元测试
      • 基准测试
      • 并发测试
      • 示例函数
      • 性能优化
      • go module
      • 在Go中使用Makefile
      • 部署Go项目
    • Golang进阶知识

    • Golang常用包

  • AIOps

  • 专栏
  • Golang
  • Golang基础知识
乔克
2025-07-13
目录

函数

函数的作用是将相同功能的代码块独立出来,用户可以重复使用。

# 函数的定义

在 Go 语言中,函数使用func关键字来定义,基本格式如下:

func 函数名(参数, ...)(返回值, ...){
    函数体
    return 返回值
}
1
2
3
4

其中:

  • 函数名:由字母、数字、下划线组成,不能以数字开头,推荐驼峰式命名方式。在同一个包里函数名不能同名;
  • 参数:参数由参数变量和参数类型组成,多个参数以, 隔开;
  • 返回值:返回值由返回值变量和返回值类型组成,多个返回值以,隔开;

例如:

func sum(x int,y int)(sum int){
	return x +y
}
1
2
3

说明:函数的参数和返回值是可选的。

# 函数的调用

定义好函数之后,我们可以通过函数名()的方式调用函数。

例如:

package main

import "fmt"

func sum(x int, y int) (sum int) {
	return x + y
}

func main() {
	// 调用函数
	ret := sum(10, 20)
	fmt.Println(ret)
}
1
2
3
4
5
6
7
8
9
10
11
12
13

注意:如果调用的函数有返回值,我们可以像上面例子中接收这个返回值,我们也可以不接收。

# 函数的其他定义方式

# 类型简写

如果函数的参数中相邻两个参数的类型相同,我们可以把前面的参数类型省略。如下:

func f1(x, y int) (sum int) {
	return x + y
}
1
2
3

如上即为 x 和 y 都是 int 类型。

# 返回值变量省略

上面介绍返回值包含返回值变量和返回值类型,其中的返回值变量可以省略。如下:

func f1(x, y int) int {
	return x + y
}
1
2
3

这两种的区别:如果在函数定义的时候写了返回值变量,我们在函数体中可以直接使用这个变量,而且在 return 的时候可以不写这个变量,如下:

func f1(x, y int) (sum int) {
	sum = x + y
	return
}
1
2
3
4

# 可变参数

可变参数是指函数的参数不固定,在 Go 语言中的可变参数通过在参数后面加... 来标识。

如下:

func sum(x int, y ...int) int{
    sum := x
    for _, v := range y{
        sum += v
    }
    return sum
}
1
2
3
4
5
6
7

注意:

  • 可变参数必须放在参数的最后面;
  • 可变参数是一个切片,比如上面定义的 y 就是一个切片;

# 函数的进阶

# 变量的作用域

# 全局变量

在 Go 语言中定义在函数外部的变量即为全局变量,该变量在程序的整个生命周期都有效,函数中可以访问到全局变量。

该变量的定义必须有关键字var。如下:

package main

import "fmt"

// 全局变量
// 定义一个全局变量
var a = 100

func main() {
	fmt.Println(a) // 输出:100
}
1
2
3
4
5
6
7
8
9
10
11

# 局部变量

在 Go 语言中,有两种局部变量:

  • 定义在函数内,函数内都可以使用;
  • 只在函数内某个代码块中使用,代码块执行完,该变量就失效了;

对于第一种,示例如下:

package main

import "fmt"

// 全局变量
// 定义一个全局变量
var a = 100

// 定义一个函数
func f1() {
	b := 200
	fmt.Println(b)
}

func main() {
	fmt.Println(a) // 输出:100
	// 调用函数
	f1()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

对于第二种,示例如下:

package main

import "fmt"

// 全局变量
// 定义一个全局变量
var a = 100

// 定义一个函数
func f2() {
	if a := 19; a > 10 {
		fmt.Println(a)
	} else {
		fmt.Println("No BB")
	}
}
func main() {
	fmt.Println(a) // 输出:100
	// 调用函数
	f2()
}
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"

// 全局变量
// 定义一个全局变量
var a = 100

// 定义一个函数
func f1() {
	a := 200
	fmt.Println(a) // 输出:200
}

func main() {
	fmt.Println(a) // 输出:100
	// 调用函数
	f1()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 函数类型与变量

# 函数类型

在 Go 语言中,可以用type关键字来定义函数类型。如下:

type myFunc func(int,int) int
1

上面就定义了一个myFunc类型,它是一个函数类型,它接收两个 int 参数并返回一个 int 类型的返回值。

凡是满足这类条件的函数都是myFunc类型的函数,比如下面的add和sub 函数都是myFunc类型的函数:

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}
1
2
3
4
5
6
7

那么就可以把add和sub 赋值给myFunc的变量,如下:

package main

import "fmt"

func sum(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}
func main() {
	type myFunc func(int, int) int
	var test myFunc
	test = sum
	fmt.Println(test(1, 2))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 函数类型的变量

既然可以定义函数类型,那么就可以通过该类型来声明变量,这个变量可以进行赋值操作,这个赋值的变量须满足该类型的条件,如上。

# 高阶函数

# 函数作为参数

函数可以作为参数传递到其他函数中,如下:

package main

import "fmt"

func f1(x, y int) int {
	return x + y
}

func f2(a, b int, f func(int, int) int) int {
	sum := f(a, b)
	return sum
}

func main() {
	ret := f2(1, 2, f1)
	fmt.Println(ret)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在f2的函数中定义了三个参数:a、b、f。其中 a,b 就是普通的 int 类型的参数,f 是一个函数参数,这个函数需要传入两个 int 类型的参数并返回一个 int 类型的返回值。

# 函数作为返回值

函数不仅可以作为参数,它还能作为返回值。如下:

package main

import "fmt"

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

func f2(x, y int) func(int, int) int {
	fmt.Println(x + y)
	return f1
}

func main() {
	ret := f2(1, 2)
	ret2 := ret(3, 4)
	fmt.Println(ret2)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

如上,在函数f2中我们定义了一个返回值,其返回值的类型是函数,所以我们在调用完f2后,接收其返回值,我们可以再一次对这个返回值做函数调用。

# 匿名函数

在 Go 语言中,函数内部不能再像之前那样定义标准的函数了,只能定义匿名函数。所谓的匿名函数就是没有函数名的函数。如下:

func(参数)(返回值){
    函数体
}
1
2
3

由于匿名函数没有函数名,所以不能像普通函数那样调用。要运行匿名函数有以下两种方式。

第一种,用一个变量去接收匿名函数,然后通过变量来调用函数。如下:

package main

import "fmt"

func main() {
	// 定义一个匿名函数,用变量去接收
	f1 := func(x, y int) int {
		return x + y
	}
	// 通过变量去调用执行函数
	ret := f1(1, 2)
	fmt.Println(ret)
}
1
2
3
4
5
6
7
8
9
10
11
12
13

第二种,自动执行匿名函数。如下:

package main

import "fmt"

func main() {
	// 定义一个匿名函数自动执行
	func(x, y int) {
		fmt.Println(x + y)
	}(1, 2)
}
1
2
3
4
5
6
7
8
9
10

当然,如果这个匿名函数有返回值,而且要接收这个返回值,我们依然要用一个变量去接收它,如下:

package main

import "fmt"

func main() {
	// 定义一个匿名函数自动执行
	ret := func(x, y int) int {
		return x + y
	}(10, 20)
	fmt.Println(ret)
}
1
2
3
4
5
6
7
8
9
10
11

# 闭包

闭包,首先是一个函数,它是定义在函数内部的函数,它由于可以读取非它本身的外部变量,就称之为闭包。

由于在 Go 语言中函数内定义函数只能用匿名函数,所以在 Go 语言中,闭包就要充分利用匿名函数。

如下:

package main

import "fmt"

func f(x int) func(int) int {
	return func(y int) int {
		return x + y
	}
}

func main() {
	f1 := f(1)
	ret := f1(2)
	fmt.Println(ret)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

上面例子中,函数f定义的函数作为返回值,所以在内部用到了匿名函数。f1变量获取到的就是返回的那个匿名函数,它里面引用了外部函数f的变量x ,这就形成了闭包。在f1的生命周期里,变量x会一直有效。

# 内部函数

内置函数 介绍
close 主要用来关闭 channel
len 用来求长度,比如 string、array、slice、map、channel
new 用来分配内存,主要用来分配值类型,比如 int、struct。返回的是指针
make 用来分配内存,主要用来分配引用类型,比如 chan、map、slice
append 用来追加元素到数组、slice 中
panic 和 recover 用来做错误处理

# 递归函数

递归函数就是自己调用自己。常用的比如计算斐波拉契,阶乘等等。

例子:假如有 n 层台阶,一次可以走 1 个,也可以走 2 个,请问有几种走法

package main

import "fmt"
func taijie(n uint) uint {
	if n == 1 {
		return 1
	}
	if n == 2 {
		return 2
	}
	return taijie(n-1) + taijie(n-2)
}

func main() {
	ret := taijie(5)
	fmt.Println(ret)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上次更新: 2025/07/18, 11:04:43
map
defer

← map defer→

最近更新
01
2025年,SRE在企业中可以做哪些事
07-18
02
SRE 如何提升自己在团队中的影响力
07-18
03
使用Go开发MCP服务
07-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式