Golang学习笔记(五):函数

键盘旁的猫
键盘旁的猫
发布时间:2026-10-14| 5人浏览过
原创

文章深入探讨了Golang中函数的核心设计,包括通过func关键字声明的基本语法、多返回值机制以及命名返回参数的使用。内容涵盖了参数传递的底层逻辑(传值与传指针的区别),并演示了如何通过…展开slice实现不定长变参。此外,详细讲解了匿名函数、闭包以及将函数作为类型和值进行传递的高级用法,为理解Go语言函数式编程范式提供了全面指导。

函数基本语法与声明

在Go语言中,函数是核心的代码组织单元,通过 func 关键字进行声明。函数的声明不需要前置原型,且左大括号 { 必须紧跟函数名,不能另起一行。

第1步:定义不同类型的函数

Go语言支持灵活的重载与重载组合(虽然不支持方法重载,但支持参数数量不同的同名函数在不同上下文使用,不过通常不推荐),具体包括:

  • 无参数无返回值:
// 一般函数
func func_name(a int) {
	println(a)
}
  • 多参数无返回值:
// 多参数,无返回值
func func_name(a, b int, c string) {
	println(a, b, c)
}
  • 单个返回值:对于相同类型的返回值,可以省略类型声明。
// 单个返回值
func func_name(a, b int) int { 
	return a + b
}
  • 多个返回值:Go支持多返回值,常用于返回结果和错误信息。
// 多个返回值,可命名返回参数
func func_name(a, b int) (c int, err error) { 
	return a+b, nil
}

第2步:了解函数限制与特性

Go语言在设计上做出了一些取舍:
- 不支持:嵌套函数(nested functions)、函数重载(overload)、默认参数(default parameters)。
- 支持:无需声明原型、不定长度变参、多返回值、命名返回值参数、匿名函数和闭包。

包的可见性由函数名的首字母决定:小写字母开头的函数仅在包内可见,大写字母开头的函数可以被其他包调用。

多返回值及命名返回参数

Go语言允许函数返回多个值,这与Python类似,但返回值不是元组(tuple),而是逗号分隔的值列表。对于不再需要的返回值,可以使用空白标识符 _ 丢弃。

第3步:使用命名返回参数

当返回参数被命名时,即使没有具体的返回值表达式,return 语句也会自动返回这些变量当前的值。但这要求变量在函数体内被正确赋值,或者显式地返回。

package main

func change(a, b int) (x, y int) {
	x = a + 100
	y = b + 100
	return // 隐式返回 x 和 y 的当前值,即 101, 102
}

func main(){
	a := 1
	b := 2
	c, d := change(a, b)
	println(c, d)
}

注意:如果命名返回参数在函数体内被局部变量遮蔽(shadowing),则必须使用显式的 return 语句来指定返回值。

参数传递:传值与传指针

Go语言中的函数参数传递默认是传值(Pass by Value),即复制一份变量的值传给函数。若要修改原变量的值或高效传递大对象,需要使用传指针(Pass by Pointer)。

第4步:理解指针操作

Go保留了指针,使用 & 取地址,使用 * 间接访问目标对象的成员。指针操作使用 . 而非 ->。

// 传值示例:副本改变,原值不变
func add1(a int) int {
	a = a + 1
	return a
}

x := 3
x1 := add1(x)
// x 仍为 3,x1 为 4
// 传指针示例:原值被修改
func add2(a *int) int {
	*a = *a + 1
	return *a
}

x := 3
x1 := add2(&x)
// x 变为 4,x1 为 4

优势与应用场景:
1. 效率:指针大小为8字节,传递大结构体时使用指针可以避免昂贵的内存拷贝。
2. 共享状态:多个函数可以通过指针操作同一个对象。
3. 特殊类型:对于 string、slice、map 这三种类型,其内部实现机制类似于指针,可以直接传递而无需额外取地址。但若需要修改 slice 的长度,仍需传递其指针。

可变参数与匿名函数

可变参数本质上是一个切片(Slice),通常位于参数列表的最后。任意类型的不定参数可以使用 interface{} 接收。

第5步:处理不定长度变参

使用 ...type 定义可变参数。调用时,如果是同类型的多个参数直接传入;如果是已有的切片,需要使用 ... 展开,否则该切片会被当作单个参数处理。

package main

func sum(s string, args ...int) {
	var x int
	for _, n := range args {
		x += n
	}
	println(s, x)
}

func main(){
	// 直接传入多个整数
	sum("1+2+3=", 1, 2, 3)

	// 展开切片
	x := []int{0, 1, 2, 3, 4}
	sum("0+1+2+3=", x[:4]...)
}

第6步:掌握匿名函数

匿名函数没有名称,通常用于需要传递简单逻辑的场景。

f := func(x, y int) int {
	return x + y
}

函数作为值和类型

在Go语言中,函数是一等公民,可以作为值存储在变量中,也可以自定义函数类型。这为实现回调、策略模式等功能提供了便利。

第7步:定义和使用函数类型

可以使用 type 关键字定义一个新的函数类型,所有拥有相同参数和返回值的函数都兼容此类型。

// 声明了一个函数类型,输入int,输出bool
type testInt func(int) bool

可以将这种类型的函数作为参数传递,例如编写一个过滤函数:

func filter(slice []int, f testInt) []int {
	var result []int
	for _, value := range slice {
		if f(value) {
			result = append(result, value)
		}
	}
	return result
}

func isOdd(integer int) bool {
	return integer%2 != 0
}

// 使用
filter([]int{1, 2, 3}, isOdd)

第8步:函数作为值的传递

函数可以是nil,可以赋值给变量,也可以作为参数传递给另一个函数(高阶函数)。

package main

// 定义函数类型 callback
type callback func(string)

// 接受另一个函数作为参数的函数
test := func(a, b int, calc func(int, int) int) {
	println(calc(a, b))
}

func main(){
	// 将匿名函数赋值给变量
	var cb callback
	cb = func(s string) {
		println(s)
	}
	cb("hello world")

	// 直接传递匿名函数
	test(1, 2, func(a, b int) int { return a + b })
}
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。