Go 函数
Go - 函数
Section titled “Go - 函数”函数是 Go(以及大多数编程语言)中的基本构建块。它们是用于执行特定任务的可重用代码块。每个 Go 程序至少包含一个函数:main(),它作为程序的入口点。
将代码分解为更小、定义明确的函数可以提高组织性、可读性和可维护性。每个函数理想情况下应具有单一、明确的目的。
函数声明(declaration)介绍其名称、参数和返回值类型。函数定义(definition)提供函数调用时实际执行的代码(函数体)。
Go 的标准库提供了许多有用的内置函数。例如,len() 可以确定字符串、数组、切片、map 和 channel 的长度。
Go 中定义函数的语法如下:
func functionName(parameterList) returnTypeList { // Body of the function: statements to execute // ... return // Optional: returns values if specified in returnTypeList}函数定义的组成部分:
func关键字: 标记函数定义的开始。functionName: 您为函数选择的名称。遵循 Go 命名约定(未导出使用 camelCase,导出使用 PascalCase)。parameterList: 括号()内的参数列表,用逗号,分隔。每个参数有一个名称后跟其类型(例如name string, age int)。如果连续参数共享相同的类型,可以省略除最后一个之外所有参数的类型(例如x, y int)。函数可以没有参数()。returnTypeList: 指定函数返回的值的类型。可以是一个类型(int),多个类型用括号括起来((string, error)),或者如果函数不返回任何值则完全省略。- 函数体: 花括号
{}包含的代码块,包含执行函数任务的语句。 return语句: 用于从函数返回值的语句。返回值的类型必须与returnTypeList匹配。如果函数没有返回值类型,return可以省略或单独使用以提前退出。
示例:查找两个整数的最大值
Section titled “示例:查找两个整数的最大值”这是一个 max 函数,它接受两个整数并返回较大的那个:
// 函数定义// 接受两个 'int' 类型参数 (num1, num2)// 返回一个 'int' 类型值func max(num1, num2 int) int { var result int // 声明一个局部变量
if num1 > num2 { result = num1 } else { result = num2 } return result // 返回计算出的最大值}要使用函数,需要通过其名称调用它,后跟括号 (),括号中包含与函数参数对应的实参(实际值)。
调用函数时,程序控制权会转移到该函数。函数执行其函数体,当遇到 return 语句或右花括号 } 时,控制权返回到函数被调用的地方。如果函数返回了值,可以将这些值赋给变量。
package main
import "fmt"
// 函数定义(同上)func max(num1, num2 int) int { if num1 > num2 { return num1 } return num2 // 简化的返回}
func main() { // 在 main 中定义局部变量 a := 100 b := 200 var maxValue int
// 使用 'a' 和 'b' 作为实参调用 'max' 函数 // 将返回值赋给 'maxValue' maxValue = max(a, b)
fmt.Printf("Max value between %d and %d is: %d\n", a, b, maxValue)}运行此程序将输出:
Max value between 100 and 200 is: 200Go 的一个独特特性是函数可以返回多个值。这通常用于同时返回一个结果和一个错误状态。
package main
import "fmt"
// 函数返回两个字符串值func swap(x, y string) (string, string) { return y, x // 先返回 y,然后返回 x}
func main() { firstName := "Alice" lastName := "Bob"
fmt.Printf("Original: %s %s\n", firstName, lastName)
// 将两个返回值赋给两个变量 swappedLast, swappedFirst := swap(firstName, lastName)
fmt.Printf("Swapped: %s %s\n", swappedFirst, swappedLast)}输出:
Original: Alice BobSwapped: Bob AliceGo 允许在函数签名中为返回值命名。这可以提高可读性,特别是对于返回多个值的函数。命名返回值会被初始化为其零值。一个裸露的 return 语句会自动返回命名返回变量的当前值。
package main
import "fmt"
// 包含命名返回值 (result int, err error) 的函数func divide(dividend, divisor int) (result int, err error) { if divisor == 0 { err = fmt.Errorf("cannot divide by zero") // 赋给命名返回值 'err' // 这里的裸露 return 将返回当前值 (result=0, err=错误) return } result = dividend / divisor // 赋给命名返回值 'result' // err 保持 nil (其零值) return // 返回 result 和 err 的当前值}
func main() { res1, err1 := divide(10, 2) if err1 != nil { fmt.Println("Error:", err1) } else { fmt.Println("10 / 2 =", res1) }
res2, err2 := divide(5, 0) if err2 != nil { fmt.Println("Error:", err2) } else { fmt.Println("5 / 0 =", res2) }}输出:
10 / 2 = 5Error: cannot divide by zero函数实参:按值传递
Section titled “函数实参:按值传递”在 Go 中,所有函数实参都是按值传递的。这意味着函数接收的是实参值的副本,而不是对原始变量的引用。
对于基本类型(如 int, float64, string, bool, 结构体),在函数内部对参数所做的修改不会影响函数外部的原始实参变量。
然而,对于切片(slice)、map 和 channel 等引用类型,被复制的值本质上是指向或描述底层数据结构的指针或头部信息。虽然指针/头部信息本身被复制了,但它仍然指向相同的底层数据。因此,在函数内部对切片或 map 的元素所做的修改会在函数外部可见。向切片追加元素可能会改变底层数组,这取决于容量是否发生变化,可能会也可能不会反映在函数外部(这是一个细微之处,通常在切片细节中讲解)。
要明确允许函数修改原始变量(如 int 或 struct),你需要传递该变量的指针(按指针传递,这在技术上仍然是按值传递,只不过传递的值是内存地址)。
| 传递机制 | 描述与影响 |
|---|---|
| 按值传递(默认) | 函数接收一个副本。内部的修改不会影响原始变量(对于基本类型/结构体)。对于切片/map,对元素的修改会影响原始变量。 |
| 按指针传递 | 函数接收内存地址(指针)的副本。通过解引用 (*ptr) 进行的修改会影响原始变量。 |
高级函数概念
Section titled “高级函数概念”| 概念 | 描述 |
|---|---|
| 可变参数函数(Variadic Functions) | 可以接受同类型可变数量参数的函数。 |
| 匿名函数(Anonymous Functions) | 没有名称的函数,通常立即使用或赋给变量。 |
| 闭包(Closures) | 捕获其周围作用域变量的匿名函数,即使外部函数执行完毕后仍能访问这些变量。 |
| 方法(Methods) | 与特定类型(接收者)关联的函数。在函数名称之前通过接收者参数定义。 |
| 延迟函数调用(Deferred Function Calls) | 使用 defer 关键字会将函数调用推迟到其所在的函数即将返回之前执行。 |