当前位置: 首页 > news >正文

Golang的函数

函数是Go语言中的基本构建块,用于组织可重用的代码逻辑。本文将详细介绍Go中函数的定义、参数传递、返回值以及高级用法。

1. 函数的基本格式

完整语法结构

func函数名(参数列表)(返回值列表){// 函数体return返回值}

组成部分说明

组成部分说明是否必需
func函数关键字必需
函数名标识函数名称必需
参数列表(参数名 参数类型, ...)可选
返回值列表(返回值名 返回值类型, ...)可选
函数体{ ... }必需
return返回语句根据返回值类型决定

2. 函数的参数传递

Go语言中的参数传递分为两种方式:值传递引用传递

值传递

值传递会将实参的值复制一份传递给函数,函数内部对参数的修改不会影响外部变量。

示例代码
packagemainimport"fmt"funcmain(){x:=12fmt.Printf("进入函数前,函数外部x的值为:%d\n",x)add(x)fmt.Printf("进入函数后,函数外部x的值还是:%d\n",x)}funcadd(xint)int{x+=12fmt.Printf("函数内部,x完成加12,值为:%d\n",x)returnx}

输出:

进入函数前,函数外部x的值为:12 函数内部,x完成加12,值为:24 进入函数后,函数外部x的值还是:12

原理分析:

外部变量 x = 12 | | 值传递:复制一份 12 ↓ 函数参数 x = 12 (独立副本) | | 函数内部修改 ↓ 函数内部 x = 24 | | 函数结束后副本销毁 ↓ 外部变量 x = 12 (不受影响)

引用传递

引用传递通过传递变量的内存地址(指针),函数内部通过指针修改数据会直接影响外部变量。

示例代码
packagemainimport"fmt"funcmain(){x:=12fmt.Printf("进入函数前,函数外部x的值为:%d\n",x)add2(&x)// 传递x的内存地址fmt.Printf("进入函数后,函数外部x的值变为:%d\n",x)}funcadd2(x*int)int{*x+=12// 通过指针修改值fmt.Printf("函数内部,x完成加12,值为:%d\n",*x)return*x}

输出:

进入函数前,函数外部x的值为:12 函数内部,x完成加12,值为:24 进入函数后,函数外部x的值变为:24

原理分析:

外部变量 x = 12 (内存地址: 0x1000) | | 引用传递:传递地址 0x1000 ↓ 函数参数 x = 0x1000 (指针) | | 通过地址修改内存 ↓ *操作符解引用,修改地址0x1000的值 | ↓ 外部变量 x = 24 (同一块内存被修改)

值传递 vs 引用传递对比

对比维度值传递引用传递(指针)
传递内容数据的副本数据的内存地址
内存占用复制整个数据只复制指针(8字节)
修改影响不影响外部变量影响外部变量
大对象性能开销较大开销较小
安全性高(不会意外修改外部数据)需要谨慎使用
语法标识直接传值使用&取地址和*解引用

3. 函数的参数类型

多个参数

funcadd(aint,bint)int{returna+b}// 连续参数类型可以简写funcadd(a,bint)int{returna+b}

可变参数

funcsum(nums...int)int{total:=0for_,num:=rangenums{total+=num}returntotal}// 调用方式result:=sum(1,2,3,4,5)// result = 15

4. 函数的返回值

单返回值

funcadd(aint,bint)int{returna+b}

多返回值

funcdivide(a,bint)(int,error){ifb==0{return0,fmt.Errorf("除数不能为零")}returna/b,nil}

命名返回值

funcgetCoordinates()(x,yint){x=10y=20return// 裸返回,自动返回x和y}

5. 匿名函数和闭包

匿名函数

// 定义并立即执行funcmain(){result:=func(a,bint)int{returna+b}(10,20)fmt.Println(result)// 30}

闭包(Closure)

funcgetCounter()func()int{count:=0returnfunc()int{count++returncount}}funcmain(){counter:=getCounter()fmt.Println(counter())// 1fmt.Println(counter())// 2fmt.Println(counter())// 3}

6. 函数作为类型

定义函数类型

typeOperationfunc(int,int)intfuncadd(a,bint)int{returna+b}funcsubtract(a,bint)int{returna-b}funcmain(){varop Operation op=add fmt.Println(op(10,5))// 15op=subtract fmt.Println(op(10,5))// 5}

函数作为参数

funccalculate(a,bint,opfunc(int,int)int)int{returnop(a,b)}funcmain(){result:=calculate(10,5,func(a,bint)int{returna*b})fmt.Println(result)// 50}

7. defer延迟执行

defer语句用于在函数返回前执行某些操作,常用于资源清理。

funcreadFile(){file,err:=os.Open("test.txt")iferr!=nil{return}deferfile.Close()// 函数返回前自动关闭文件// 读取文件内容...fmt.Println("读取文件成功")}

defer的特性

  • 多个defer按后进先出(LIFO)顺序执行
  • defer在函数返回之前执行
  • defer的参数在定义时就已经确定
funcdeferExample(){deferfmt.Println("第三")deferfmt.Println("第二")deferfmt.Println("第一")fmt.Println("开始执行")}// 输出:// 开始执行// 第一// 第二// 第三

8. init函数

init函数在包初始化时自动执行,用于初始化包级别的变量。

packagemainimport"fmt"funcinit(){fmt.Println("init函数执行")}funcmain(){fmt.Println("main函数执行")}// 输出:// init函数执行// main函数执行

9. 完整示例程序

packagemainimport"fmt"funcmain(){// 值传递示例fmt.Println("=== 值传递 ===")x:=12fmt.Printf("进入函数前,函数外部x的值为:%d\n",x)add(x)fmt.Printf("进入函数后,函数外部x的值还是:%d\n\n",x)// 引用传递示例fmt.Println("=== 引用传递 ===")y:=12fmt.Printf("进入函数前,函数外部y的值为:%d\n",y)add2(&y)fmt.Printf("进入函数后,函数外部y的值变为:%d\n\n",y)// 多返回值示例fmt.Println("=== 多返回值 ===")quotient,remainder:=divide(17,5)fmt.Printf("17 / 5 = %d 余 %d\n\n",quotient,remainder)// 闭包示例fmt.Println("=== 闭包示例 ===")counter:=getCounter()fmt.Println(counter())fmt.Println(counter())fmt.Println(counter())}// 值传递函数funcadd(xint)int{x+=12fmt.Printf("函数内部,x完成加12,值为:%d\n",x)returnx}// 引用传递函数(指针)funcadd2(x*int)int{*x+=12fmt.Printf("函数内部,x完成加12,值为:%d\n",*x)return*x}// 多返回值函数funcdivide(a,bint)(int,int){returna/b,a%b}// 闭包函数funcgetCounter()func()int{count:=0returnfunc()int{count++returncount}}
  1. 函数命名:使用驼峰命名法,导出函数首字母大写
  2. 单一职责:每个函数只做一件事
  3. 参数数量:尽量避免超过5个参数
  4. 错误处理:多返回error类型进行错误处理
  5. 避免副作用:尽量保持函数的纯粹性
  6. 适当注释:为导出的函数添加注释说明
http://www.jsqmd.com/news/1067267/

相关文章:

  • 中科蓝讯-双耳未连接手机,主耳入仓从耳不能播报配对提示音
  • 零基础做量化,先把学习路径拆成几段
  • 软件工程领域 LLM 驱动的自迭代知识引擎
  • 有经验的防水施工队看年限
  • InDraw如何将化合物的名称转为结构式?
  • 考试作弊识别数据集 基于YOLOv8的考试作弊报警系统(数据集+界面+模型)
  • AScript定制left/right join查询语法
  • 蚂蚁面试官:“你的 Agent 怎么触发记忆提取?“ 我不屑:“每轮结束触发一次呗。“ 他冷笑:“那 Claude Code 为什么不这么设计?“ 我:……
  • 2026 年 AI 音效赛道技术现状:三款国产方案横向对比
  • 网络管理作业
  • C语言小游戏 — 三子棋
  • OpenClaw-RL
  • 运维监控大屏踩坑记:一条 SQL 的“CASE 陷阱”与跨库优化实践
  • 文字编辑器EditPlus
  • 2026年SEO+GEO优化指南:搜索排名机制解析与实用工具推荐
  • 搬瓦工 KiwiVM 面板免费 AI 助手 Amy 功能演示 | 告别繁琐的命令行
  • 【Azure Function App】本地调试PowerShell Function时需要注意两类错误:加载失败和认证失败
  • 前端学习笔记-vue组件通信常用方式
  • 在本地运行任意 Hugging Face 模型:GGUF 完全指南
  • 2026最权威AI论文写作工具榜单:这些被高校和导师偷偷推荐的软件你还没用?
  • OpenTracing Python:分布式追踪的标准 API
  • 先说基因:一个做自动化起家,一个做采集起家
  • AI写作辅助软件的使用规范:如何让AI生成内容通过严格学术审查
  • 我做了一个只用来搜歌词的小 App
  • 非对称密码体系的密码分析方法研究
  • Pendulum:Python 日期时间处理的终极解决方案
  • 告别新手级RAG!一文掌握专业级后检索优化之「校正」
  • Edge浏览器停止更新,并回退到老版本方法
  • 深入 .NET AI Agent 开发:利用 Microsoft.Agents.AI 提取思考、调用工具与执行脚本
  • Manim物理模拟:别自己写欧拉了!