☰
【Go语言基础【13】】函数、闭包、方法
2026/11/3 1:24:43 网站建设 项目流程

文章目录

  • 零、概述
  • 一、函数基础
    • 1、函数基础概念
    • 2、参数传递机制
    • 3、返回值特性
      • 3.1. 多返回值
      • 3.2. 命名返回值
      • 3.3. 错误处理
  • 二、函数类型与高阶函数
    • 1. 函数类型定义
    • 2. 高阶函数(函数作为参数、返回值)
  • 三、匿名函数与闭包
    • 1. 匿名函数(Lambda函数)
    • 2. 闭包(Closure)
  • 四、内置函数
  • 五、方法(让go有了面向对象的特性)

零、概述

函数核心特性速查

特性说明
多返回值支持同时返回结果和错误(如(int, error))
可变参数通过...Type定义,本质为切片([]Type)
函数类型可定义函数类型(如type FuncType func(int) bool)
闭包匿名函数捕获外部变量,保持状态
方法绑定到结构体的函数,通过接收者参数(func (t Type) Method())定义
内置函数len、make、append等预定义函数,直接使用

最佳实践

  1. 错误处理
    • 多返回值中优先返回错误(如func() (Result, error))。
    • 使用if err != nil判断错误,避免忽略重要异常。
  2. 减少值拷贝
    • 传递大结构体时使用指针(*T),避免性能损耗。
    • 切片、map等引用类型默认传递指针,无需额外处理。
  3. 函数职责单一
    • 每个函数专注完成一个独立功能,符合单一职责原则。
    • 避免函数过长(建议不超过50行),复杂逻辑拆分为子函数。

一、函数基础

1、函数基础概念

Go语言中的函数可赋值给变量、作为参数传递或作为返回值,极大提升了编程灵活性。

1. 函数定义语法

func函数名(参数列表)(返回值列表){函数体return返回值}
  • 参数列表:参数类型需后置,连续相同类型可合并声明。
    funcsum(x,yint)int{// x, y 均为 int 类型returnx+y}
  • 返回值列表:可无返回值或多返回值(用括号包裹),支持命名返回值。
    funcdiv(x,yint)(int,error){// 多返回值ify==0{return0,errors.New("除数不能为0")}returnx/y,nil}

2、参数传递机制

1.1. 值传递

  • 机制:传递参数的副本,函数内修改不影响原始值。
  • 适用场景:小数据类型(如int、string)或无需修改原始值的场景。
    funcmodifyValue(xint){x=100// 仅修改副本}funcmain(){a:=20modifyValue(a)// a 仍为 20}

1.2. 引用传递

  • 机制:传递参数的地址(通过指针*T),函数内可修改原始值。
  • 适用场景:大数据类型(如结构体)或需修改原始值的场景。
    funcmodifyPointer(x*int){*x=100// 修改原始值}funcmain(){a:=20modifyPointer(&a)// a 变为 100}

1.3. 可变参数
语法:通过...Type定义可变参数,本质为切片。

funcsum(nums...int)int{// nums 类型为 []inttotal:=0for_,num:=rangenums{total+=num}returntotal}funcmain(){sum(1,2,3)// 等价于 sum([]int{1,2,3})}

3、返回值特性

3.1. 多返回值

用途:同时返回结果和错误(Go语言的惯用模式)。

funcreadFile(pathstring)([]byte,error){data,err:=os.ReadFile(path)returndata,err}

3.2. 命名返回值

语法:为返回值命名,函数体可直接使用(类似变量声明)。

funccalculate(x,yint)(sum,productint){// 命名返回值sum=x+y product=x*yreturn// 隐式返回 sum, product}

3.3. 错误处理

丢弃返回值:用_忽略不关心的返回值。

data,_:=readFile("data.txt")// 忽略错误

二、函数类型与高阶函数

1. 函数类型定义

在Go语言中,函数类型定义是指为一种特定的函数签名创建一个自定义类型名称。这样可以让具有相同签名的函数共享同一个类型(有点面向接口开发的感觉)。

typeCalculatorfunc(int,int)int// 定义函数类型// 这些函数都符合Calculator类型的签名funcadd(x,yint)int{returnx+y}funcsubtract(x,yint)int{returnx-y}funcmultiply(x,yint)int{returnx*y}funcdivide(x,yint)int{returnx/y}

例题:

packagemainimport"fmt"typeCalculatorfunc(int,int)intfuncadd(x,yint)int{returnx+y}funcsubtract(x,yint)int{returnx-y}// 使用函数类型作为参数funccalculate(calc Calculator,a,bint)int{returncalc(a,b)}// 使用函数类型作为变量funcmain(){varmyCalc Calculator myCalc=add fmt.Println(myCalc(5,3))// 输出: 8myCalc=subtract fmt.Println(myCalc(5,3))// 输出: 2// 作为参数传递result:=calculate(add,10,5)fmt.Println(result)// 输出: 15}

2. 高阶函数(函数作为参数、返回值)

函数作为参数:

funcoperate(x,yint,fn Calculator)int{// 接收函数作为参数// 作为参数的函数,来处理参数returnfn(x,y)}funcmain(){result:=operate(10,5,add)// 调用 add 函数}


函数作为返回值:
在Go语言中,函数可以作为返回值,这使得我们可以创建闭包。闭包是一个函数,它可以捕获并记住其所在环境中的变量。

funcmakeAdder(nint)Calculator{// 返回函数returnfunc(xint)int{returnx+n}}funcmain(){add5:=makeAdder(5)// add5(3) 返回 8}

三、匿名函数与闭包

1. 匿名函数(Lambda函数)

  • 无名称函数,可直接定义和调用:
// 赋值给变量greet:=func(){fmt.Println("Hello, Go!")}greet()// 调用匿名函数1.定义:func(){...}是一个匿名函数,因为它没有名称。2.赋值:我们将这个匿名函数赋值给变量greet。3.调用:通过greet()来调用这个匿名函数。// 立即执行函数表达式(IIFE)result:=func(x,yint)int{returnx*y}(3,4)1.定义并执行:func(x,yint)int{returnx*y}是一个匿名函数。2.立即执行:在定义后面紧跟(3,4),这表示立即用参数3和4调用这个函数。3.结果:函数返回3*4的结果12,并将其赋值给变量result。

2. 闭包(Closure)

定义:匿名函数捕获外部变量形成闭包,变量在闭包内保持状态。

闭包能够捕获并记住其外部环境中的变量,即使在函数执行完毕后,这些变量仍然可以被访问和修改。这使得闭包可以在不同的调用之间保持状态,例如计数器、缓存等。

packagemainimport"fmt"// adder 返回一个闭包函数,该函数捕获了外部变量 sumfuncadder()func(int)int{sum:=0// 这是被闭包捕获的外部变量returnfunc(xint)int{sum+=x// 每次调用时,更新并返回 sumreturnsum}}funcmain(){pos:=adder()// 创建一个新的闭包fmt.Println(pos(1))// 输出: 1fmt.Println(pos(2))// 输出: 3fmt.Println(pos(3))// 输出: 6// 创建另一个独立的闭包neg:=adder()fmt.Println(neg(-1))// 输出: -1fmt.Println(neg(-2))// 输出: -3}

四、内置函数

Go语言预定义了一组内置函数,无需导入包即可使用:

函数名功能描述
len()获取切片、字符串、通道等的长度
new()分配零值内存,返回指针(如new(int)返回*int)
make()创建引用类型(切片、map、通道)并初始化
append()向切片追加元素,返回新切片
panic()触发运行时恐慌,用于错误处理
recover()在defer中恢复恐慌,避免程序崩溃

五、方法(让go有了面向对象的特性)

在Go语言中,方法和函数的主要区别在于方法是绑定到特定类型的,而函数则是独立的。

packagemainimport("fmt""math")typeCirclestruct{radiusfloat64}func(c Circle)area()float64{returnmath.Pi*c.radius*c.radius}func(c*Circle)updateRadius(rfloat64){c.radius=r}funccalculateArea(radiusfloat64)float64{returnmath.Pi*radius*radius}funcmain(){c:=Circle{radius:5}// 调用方法fmt.Println("Area using method:",c.area())// 使用方法计算面积// 更新半径c.updateRadius(10)fmt.Println("Updated area using method:",c.area())// 调用函数fmt.Println("Area using function:",calculateArea(5))// 使用函数计算面积}

通过方法,Go语言实现了面向对象编程的特性,使得类型可以拥有自己的行为。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询