第四篇:《函数、指针与结构体:组织代码的核心工具》
变量是代码的“名词”函数是代码的“动词”。在 Go 语言中函数是第一公民支持多返回值、命名返回值和闭包。指针提供了对内存的间接访问能力但 Go 的指针比 C 更安全——不支持指针算术。结构体struct是 Go 组织数据的核心方式结合方法method可以实现面向对象编程中的“类”概念。本文系统讲解函数、指针与结构体的核心语法与最佳实践并通过一个“学生管理系统”的实战案例帮你掌握组织 Go 代码的核心工具。一、函数Go 代码的组织单元1.1 函数的基本声明Go 函数的声明格式为func 函数名(参数列表) 返回值列表 { 函数体 }// 无参数无返回值funcsayHello(){fmt.Println(Hello!)}// 带参数funcgreet(namestring){fmt.Printf(Hello, %s!\n,name)}// 带返回值funcadd(aint,bint)int{returnab}// 参数类型相同时可以省略前一个的类型声明funcmultiply(a,bint)int{returna*b}1.2 多返回值Go 的特色Go 是少数支持多返回值的语言之一这是 Go 错误处理机制的基础// 返回两个值商和余数funcdivide(a,bint)(int,int){quotient:a/b remainder:a%breturnquotient,remainder}funcmain(){q,r:divide(10,3)fmt.Printf(商: %d, 余数: %d\n,q,r)// 商: 3, 余数: 1// 如果不需要某个返回值使用空白标识符 _q2,_:divide(20,6)fmt.Println(商:,q2)}1.3 命名返回值Go 允许为返回值命名这在函数体中可以像普通变量一样使用return 语句可以不带参数自动返回// 命名返回值funcdivideWithName(a,bint)(quotientint,remainderint){quotienta/b remaindera%breturn// 裸返回返回 quotient 和 remainder}// 在文档中更清晰funcgetUserInfo(idint)(namestring,ageint,emailstring){// 实际开发中这里会从数据库查询nameAliceage30emailaliceexample.comreturn} 使用建议对于短函数1-3 行命名返回值可能增加代码冗余对于长函数或返回多个相同类型值时命名返回值能提高可读性。1.4 可变参数使用 …T 语法接收任意数量的参数// 求和支持任意数量的参数funcsum(nums...int)int{total:0for_,num:rangenums{totalnum}returntotal}funcmain(){fmt.Println(sum(1,2,3))// 6fmt.Println(sum(1,2,3,4,5))// 15// 传入切片时使用 ... 展开nums:[]int{1,2,3,4}fmt.Println(sum(nums...))// 10}1.5 匿名函数与闭包Go 支持在函数内部定义匿名函数并可以捕获外部变量闭包// 匿名函数直接调用funcmain(){func(msgstring){fmt.Println(msg)}(Hello from anonymous!)}// 闭包函数捕获外部变量funccounter()func()int{count:0returnfunc()int{countreturncount}}funcmain(){c:counter()fmt.Println(c())// 1fmt.Println(c())// 2fmt.Println(c())// 3}二、指针内存的“门牌号”Go 的指针提供了对变量内存地址的访问能力但比 C 更安全——不支持指针算术运算如 p。2.1 指针的基本操作funcmain(){x:42p:x// p 是指向 x 的指针类型为 *intfmt.Println(p)// 内存地址如 0xc00000a0a8fmt.Println(*p)// 解引用输出 42*p100// 通过指针修改 x 的值fmt.Println(x)// 输出 100}2.2 值传递 vs 指针传递Go 中所有参数都是值传递传递副本但对于大型数据结构使用指针传递可以避免拷贝开销并能修改原值// 值传递函数内修改不影响外部funcupdateValue(vint){v100}// 指针传递函数内修改影响外部funcupdatePointer(p*int){*p100}funcmain(){a:10updateValue(a)fmt.Println(a)// 10未改变updatePointer(a)fmt.Println(a)// 100已改变}2.3 指针接收者 vs 值接收者与结构体方法相关在 Go 中方法可以定义在结构体上接收者可以是值或指针typePersonstruct{NamestringAgeint}// 值接收者不能修改原值func(p Person)SayHello(){fmt.Printf(你好我是 %s今年 %d 岁\n,p.Name,p.Age)}// 指针接收者可以修改原值func(p*Person)SetAge(ageint){p.Ageage}funcmain(){p:Person{Name:Alice,Age:30}p.SetAge(31)// 可以修改原值p.SayHello()// 你好我是 Alice今年 31 岁}选择原则需要修改结构体字段 → 使用指针接收者结构体较大 64 字节 → 使用指针接收者避免拷贝开销结构体较小且不需要修改 → 可以使用值接收者三、结构体Struct组合数据的载体Go 没有类的概念但通过结构体和方法可以实现面向对象编程的核心能力。3.1 定义与初始化// 定义结构体typeStudentstruct{IDintNamestringAgeintScores[]int}// 多种初始化方式funcmain(){// 方式1按字段顺序不推荐可读性差s1:Student{1,Alice,20,[]int{90,85,92}}// 方式2使用字段名推荐s2:Student{ID:2,Name:Bob,Age:21,}// 方式3先声明再赋值零值初始化vars3 Student s3.ID3s3.NameCharlie// 方式4使用 new 关键字返回指针s4:new(Student)// *Student 类型s4.ID4s4.NameDavid}3.2 匿名结构体适用于一次性使用的场景funcmain(){// 匿名结构体直接初始化config:struct{HoststringPortint}{Host:localhost,Port:8080,}fmt.Printf(%v\n,config)// {Host:localhost Port:8080}}3.3 结构体嵌套Go 支持结构体嵌套可以实现类似继承的效果typeAddressstruct{CitystringCountrystring}typeEmployeestruct{NamestringAgeintAddress Address// 嵌套结构体}funcmain(){e:Employee{Name:Alice,Age:30,Address:Address{City:Beijing,Country:China,},}// 访问嵌套字段fmt.Println(e.Address.City)// Beijing}3.4 匿名字段嵌入式结构体Go 支持“嵌入”结构体被嵌入的字段可以直接访问typeEmployeestruct{NamestringAgeintAddress// 匿名字段嵌入式}funcmain(){e:Employee{Name:Alice,Age:30,Address:Address{City:Beijing,Country:China,},}// 可以直接访问嵌入的字段fmt.Println(e.City)// Beijing不需要 e.Address.Cityfmt.Println(e.Country)// China}四、实战学生管理系统综合运用结构体、方法和函数实现一个简单的学生管理系统packagemainimportfmt// 学生结构体typeStudentstruct{IDintNamestringScores[]float64}// 计算平均分func(s Student)Average()float64{iflen(s.Scores)0{return0}total:0.0for_,score:ranges.Scores{totalscore}returntotal/float64(len(s.Scores))}// 判断是否及格平均分 60func(s Student)IsPassed()bool{returns.Average()60}// 学生管理系统typeStudentManagerstruct{Studentsmap[int]Student}// 添加学生func(sm*StudentManager)AddStudent(s Student){ifsm.Studentsnil{sm.Studentsmake(map[int]Student)}sm.Students[s.ID]s}// 根据 ID 查找学生func(sm*StudentManager)FindByID(idint)(Student,bool){s,ok:sm.Students[id]returns,ok}// 列出所有学生信息func(sm*StudentManager)ListAll(){iflen(sm.Students)0{fmt.Println(暂无学生数据)return}fmt.Println( 学生列表 )for_,s:rangesm.Students{fmt.Printf(ID: %d, 姓名: %s, 平均分: %.2f, 状态: %s\n,s.ID,s.Name,s.Average(),map[bool]string{true:及格,false:不及格}[s.IsPassed()])}}funcmain(){sm:StudentManager{}// 添加学生sm.AddStudent(Student{ID:1,Name:Alice,Scores:[]float64{90,85,92}})sm.AddStudent(Student{ID:2,Name:Bob,Scores:[]float64{50,60,55}})sm.AddStudent(Student{ID:3,Name:Charlie,Scores:[]float64{70,75,80}})// 查找学生ifs,ok:sm.FindByID(2);ok{fmt.Printf(找到学生: %s, 平均分: %.2f\n,s.Name,s.Average())}// 列出所有sm.ListAll()}五、小结函数支持多返回值、命名返回值、可变参数和闭包是 Go 代码的基本组织单元。指针使用 取地址* 解引用不支持指针算术。指针传递允许修改原值避免拷贝开销。结构体组合数据的核心方式支持嵌套和匿名字段。方法可以定义在值接收者或指针接收者上。选择原则需要修改字段时用指针接收者不需要修改且结构体较小时用值接收者。

相关新闻

【超详细】二分查找(折半查找)核心知识点全解析(含多场景代码实现)

【超详细】二分查找(折半查找)核心知识点全解析(含多场景代码实现)

一、前言二分查找(Binary Search)是算法领域最经典、最高效的查找算法之一,其时间复杂度为 O(logn),相比顺序查找的 O(n) 效率提升呈指数级。它是「分治思想」的典型应用,也是面试中高频考察的算法考点。本文将从核心概…

2026/7/22 23:13:03 阅读更多 →
针对络合态重金属废水,探索集成Tulsimer 树脂的深度处理与资源回收工艺

针对络合态重金属废水,探索集成Tulsimer 树脂的深度处理与资源回收工艺

在日益严格的环保政策与循环经济需求的双重驱动下,许多工业企业正面临重金属废水治理的深层挑战:络合态重金属难以稳定达标、危废处置成本高昂、以及有价值金属资源的流失。传统沉淀、氧化等工艺在处理此类废水时,往往遇到瓶颈。本文将探讨一…

2026/7/22 23:13:03 阅读更多 →
Tiva™ TM4C129XNCZAD寄存器编程实战:从模块化理解到高效驱动开发

Tiva™ TM4C129XNCZAD寄存器编程实战:从模块化理解到高效驱动开发

1. 从寄存器列表到高效编程:Tiva™ TM4C129XNCZAD 实战指南看到这份长长的寄存器列表,很多刚接触 Tiva™ TM4C129XNCZAD 或者从 Arduino 这类高级框架转过来的朋友可能会有点懵。手册里几百个寄存器,每个都有一堆位域,难道写个点灯…

2026/7/22 23:13:03 阅读更多 →

最新新闻

终极OpenGL开发利器Epoxy:从安装到实战的快速入门教程

终极OpenGL开发利器Epoxy:从安装到实战的快速入门教程

终极OpenGL开发利器Epoxy:从安装到实战的快速入门教程 【免费下载链接】libepoxy Epoxy is a library for handling OpenGL function pointer management for you 项目地址: https://gitcode.com/gh_mirrors/li/libepoxy Epoxy是一款强大的OpenGL函数指针管理…

2026/7/22 23:55:24 阅读更多 →
0721晨间日记

0721晨间日记

# 0721晨间日记 - 关键词 - 上午- 数据分类- 锡膏和炉子的对比的数据- L5线的电容的偏移的问题- 依据不良的板子的查询炉前 炉后的条码- 到底炉前偏移成什么样子了- 炉后成为什么样子了- 到底偏移和角度是不是有设置?- - 下午- 数据的分类- - L1的条码的问题- 用Py…

2026/7/22 23:55:24 阅读更多 →
【优化求解】基于自适应变异麻雀搜索算法求解单目标优化问题matlab代码(AMSSA)

【优化求解】基于自适应变异麻雀搜索算法求解单目标优化问题matlab代码(AMSSA)

1 简介针对麻雀搜索算法前期易陷入局部极值点、后期寻优精度不高等问题,提出一种自适应变异麻雀搜索算法(AMSSA)。首先,通过猫映射混沌序列初始化种群,增强初始种群的随机性、遍历性,提高算法的全局搜索能力…

2026/7/22 23:55:24 阅读更多 →
为什么选择ETH.Build?5个理由让它成为Web3开发者的必备教育平台

为什么选择ETH.Build?5个理由让它成为Web3开发者的必备教育平台

为什么选择ETH.Build?5个理由让它成为Web3开发者的必备教育平台 【免费下载链接】eth.build 🛠🧮 Educational sandbox for building on web3. Visually understand how Ethereum works by doing. 项目地址: https://gitcode.com/gh_mirror…

2026/7/22 23:55:24 阅读更多 →
数据乱成一锅粥?别慌!这几位“数据管家”总有一款适合你

数据乱成一锅粥?别慌!这几位“数据管家”总有一款适合你

企业做大了,最头疼的就是数据各说各话。别急,国内主数据管理(MDM)圈儿的几位“大神”来救场了,我们给你挨个扒一扒。 先说中翰软件,妥妥的“老法师”,2010年就搞出了国内第一个企业MDM平台。它家…

2026/7/22 23:55:24 阅读更多 →
USB设备中断服务例程(ISR)设计:从原理到实战的嵌入式开发指南

USB设备中断服务例程(ISR)设计:从原理到实战的嵌入式开发指南

1. USB设备中断服务例程(ISR)的核心价值与设计挑战在嵌入式系统里做USB设备开发,中断服务例程(ISR)的设计绝对是整个固件架构的“心脏”。它直接决定了你的设备能否稳定、高效地与主机“对话”。很多刚接触USB协议栈的…

2026/7/22 23:54:24 阅读更多 →

日新闻

TI DSP系统配置模块SYSCFG详解:中断机制与主设备优先级配置实战

TI DSP系统配置模块SYSCFG详解:中断机制与主设备优先级配置实战

1. 项目概述与SYSCFG模块的核心价值在嵌入式系统,尤其是像TI C6000系列这样的高性能DSP开发中,我们常常会与芯片手册里那些密密麻麻的寄存器打交道。很多开发者可能更关注算法实现、内存优化或者外设驱动,但对于一个稳定、高效的系统而言&…

2026/7/22 0:00:26 阅读更多 →
微信Server酱:高到达率的应急通知方案实践

微信Server酱:高到达率的应急通知方案实践

1. 为什么我们需要"最次"的通知方案? 在数字化协作环境中,消息通知系统的重要性不言而喻明。但现实情况是,企业级通知方案往往需要复杂的API对接(如企业微信、钉钉、飞书),个人开发者的小项目又经…

2026/7/22 0:00:26 阅读更多 →
甲方要的“简洁“PPT,到底是简洁还是省事?

甲方要的“简洁“PPT,到底是简洁还是省事?

甲方说"简洁一点",乙方听到的是"少做几页"。甲方说"不要太复杂",乙方理解成"别放图表了"。结果交过去,甲方说"我说的简洁不是这个意思"。"简洁"这个词在PPT语境里,是…

2026/7/22 0:00:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/22 12:54:44 阅读更多 →

月新闻