Go语言中的函数详解
本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《Go语言中的函数详解》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~
1.函数的声明定义
//func关键字
//getStudent函数名
//(id int, classId int) 参数列表
//(name string,age int) 返回值列表
func getStudent(id int, classId int)(name string,age int) {
//函数体
if id==1&&classId==1{
name = "BigOrange"
age = 26
}
//返回值
return name, age // 支持多重返回值
}
有意思的是Go语言的返回值可以有多个,并且放在了参数列表后面,而C#等都是在函数名之前,也没有关键字。
2.函数的调用
import "fmt"
//调用fmt包中的Println方法。
fmt.Println("Name:", std.Name, "Age:",std.Age)
3.函数编写的原则
很好奇为什么没有public private等关键字,那函数怎么才能定义为公用和私有呢?
Go语言有这样的规则:小写字母开头的函数只在本包内可见,大写字母开头的函数才
能被其他包使用。这个规则也适用于类型和变量的可见性。
4.不定参数问题
不定参数是指函数传入的参数个数为不定数量。
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
函数myfunc()接受不定数量的参数,这些参数的类型全部是int
※形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。
它是一个语法糖(syntactic sugar),即这种语法对语言的功能并没有影响,但是更方便程序员使用。
从内部实现机理上来说,类型...type本质上是一个数组切片,也就是[]type,这也是为
什么上面的参数args可以用for循环来获得每个传入的参数。
不定参数的传递
myfunc3(args ...int)
对应上面的这个函数,传递参数可以为下面两种
// 按原样传递 myfunc3(args...) // 传递片段,实际上任意的int slice都可以传进去 myfunc3(args[1:]...)
任意类型的不定参数
可以看到 fmt.Println()方法接受了不定参数,但它是 ...interface{}

用interface{}传递任意类型数据是Go语言的惯例用法。
5.多返回值
Go语言函数可以返回多个返回值
如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单
地用一个下划线“_”来跳过这个返回值
6.匿名函数
Go语言支持随时在代码里定义匿名函数。
匿名函数由一个不带函数名的函数声明和函数体组成
func(a, b int, z float64) bool {
return a*b <int><p>匿名函数可以直接赋值给一个变量或者直接执行:(有点像js哈)</p>
<pre class="brush:go;">f := func(x, y int) int {
return x + y
}
func(ch chan int) {
ch
<h2>7.闭包</h2>
<pre class="brush:go;">package main
import (
"fmt"
)
func main() {
var j int = 5
a := func()(func()) {
var i int = 10
return func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
}()
a()
j *= 2
a()
}
结果:
i, j: 10, 5
i, j: 10, 10
分析:
1---"...func()(func()) {....."
表明此匿名函数返回值的类型是func(), 即此匿名函数返回一个函数指针(此处引用一下c 的概念);
2---"...returnfunc() {
fmt.Printf("i, j: %d, %d\n", i, j)
}..."
表明返回的函数指针指向一个打印i, j: %d, %d\n的函数;
3---"...a := func()(func()) {
...
}()..."
末尾的括号表明匿名函数被调用,并将返回的函数指针赋给变量a ;
综合来看:
"...a := func()(func()) {
var i int = 10
return func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
}()..."
此代码片段的意思"等价于"
a := func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
至于为何要用匿名函数如此的转一圈,是因为要引用闭包的概念,此概念省略不表,多写点代码试试就能体会了。
补充:传值和传引用

1.type 定义一个类型,有两种方式
- ①配合struct,创建一个新的结构,类似C#里面的Class
- ②配合既存的类型(int64...),创建一个新的类型,类似C++里面的typedef
2.Struct的如果不进行赋值,会使用0值进行初始化。
3.type使用既存类型定义新结构,和既存类型不是同一个类型,不能进行转换,例如
package main
type Integer int64
func main() {
var srcInt Integer
srcInt = int64(1000)
}
结果:

4.方法和函数的区别
方法能给用户定义的类型添加新的行为。方法实际上也是函数,只是在声明时,在关键字func 和方法名之间增加了一个参数
例如:
这是函数,它的调用就是直接在使用的时候 传入参数获取返回值就行
func getStudentName(student Student)(name string) {
//返回值
return student.Name
}
这是方法
package main
import (
"fmt"
)
type Student struct
{
Name string
Age int
}
//Student类的方法 使用值接收者实现了一个方法
func (student Student) getStudentName()(string){
return student.Name
}
//Student类的方法 使用指针接收者实现了一个方法
func (student *Student) changeStudentName(name string){
student.Name = name
fmt.Println("方法执行之后name",student.Name)
}
//Student类的方法 使用指针接收者实现了一个方法
func (student Student) changeStudentNameByValue(name string){
student.Name = name
fmt.Println("方法执行之后name",student.Name)
}
func main() {
bigOrange:=Student{
Name:"BigOrange",Age:18,
}
bigApple:=Student{
Name:"BigApple",Age:20,
}
//使用函数获取学生名称
name1 := getStudentName(bigOrange)
name2 := getStudentName(bigApple)
fmt.Println("========通过传地址ChangeName之后==========")
fmt.Println("方法执行之前name",name1)
bigOrange.changeStudentName("BigBanana")
name1 = bigOrange.getStudentName()
fmt.Println("方法返回之后Name",name1)
fmt.Println("========通过传值ChangeName之后===========")
fmt.Println("方法执行之前name",name2)
bigApple.changeStudentNameByValue("BigPear")
name2 = bigApple.getStudentName()
fmt.Println("方法返回之后Name",name2)
}
结果:
========通过传地址ChangeName之后==========
方法执行之前name BigOrange
方法执行之后name BigBanana
方法返回之后Name BigBanana
========通过传值ChangeName之后===========
方法执行之前name BigApple
方法执行之后name BigPear
方法返回之后Name BigApple
上面的例子中
分别使用了函数和方法进行获取学生姓名
分别使用了传值和传地址的方式对学生名称进行修正
综上
- ① Go语言中的方法,相比于函数,多了一个接收者参数
- ② Go 语言里有两种类型的接收者:值接收者和指针接收者
方法如果使用 值接收者,那么调用者可以是值接收者类型、也可以是它的指针类型,请看下面的例子(补充上例):
fmt.Println("========使用指针来调用值类型声明的接收者方法===========")
bigGrape := &Student{ Name:"bigGrape",Age:22} //取地址!!!!
name3 := bigGrape.getStudentName();
fmt.Println("========通过传值ChangeName之后===========")
fmt.Println("方法执行之前name",name3)
bigGrape.changeStudentNameByValue("BigXXXX")
name3 = bigGrape.getStudentName()
fmt.Println("方法返回之后Name",name3)
结果:
========使用指针来调用值类型声明的接收者方法===========
name bigGrape
========通过传值ChangeName之后===========
方法执行之前name bigGrape
方法执行之后name BigXXXX
方法返回之后Name bigGrape
如上代码 使用了&获取地址,所以bigGrape是一个student类型的指针。下面的代码和上例一样,直接使用了【变量.方法】的方式调用方法,结果也和值类型调用的一样。
为什么?
【Go 在代码背后的执行动作】
name4:=(*bigGrape).getStudentName()
Go 编译器为了支持这种方法调用背后做的事情。【指针被解引用为值】,这样就符合了值接收者的要求。再强调一次,getStudentName 操作的是一个副本,只不过这次操作的是从bigGrape指针指向的值的副本。
同理还记得上面的,这句代码吗?对bigOrange这个变量修改了名称
bigOrange.changeStudentName("BigBanana")
bigOrange和bigApple明显是值类型,但是 changeStudentName 接收者是一个指针类型,为什么能调用,也是基于Go代码背后的执行动作,将值类型取了地址。
(&bigOrange).changeStudentName("BigOrange")
所以对于Go语言调用方法的类型,使用值或者指针都是可以的,不用拘泥于类型。
好了,本文到此结束,带大家了解了《Go语言中的函数详解》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!
Go语言之init函数
- 上一篇
- Go语言之init函数
- 下一篇
- 分析Go错误处理优化go recover机制缺陷
-
- Golang · Go教程 | 1分钟前 |
- Golang中介者模式实现与通信解耦技巧
- 378浏览 收藏
-
- Golang · Go教程 | 6分钟前 |
- Golang多协程通信技巧分享
- 255浏览 收藏
-
- Golang · Go教程 | 26分钟前 |
- Golang如何判断变量类型?
- 393浏览 收藏
-
- Golang · Go教程 | 35分钟前 |
- Golang云原生微服务实战教程
- 310浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Golang迭代器与懒加载结合应用
- 110浏览 收藏
-
- Golang · Go教程 | 1小时前 | 性能优化 并发安全 Golangslicemap 预设容量 指针拷贝
- Golangslicemap优化技巧分享
- 412浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Golang代理模式与访问控制实现解析
- 423浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Golang事件管理模块实现教程
- 274浏览 收藏
-
- Golang · Go教程 | 2小时前 |
- Golang接口多态实现全解析
- 241浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3162次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3375次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3403次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4506次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3784次使用
-
- golang中的defer函数理解
- 2022-12-22 366浏览
-
- Golang优雅保持main函数不退出的办法
- 2023-01-07 272浏览
-
- Go语言中函数可变参数(VariadicParameter)详解
- 2023-01-07 312浏览
-
- go语言中函数与方法介绍
- 2023-01-07 297浏览
-
- Go语言中make和new函数的用法与区别
- 2022-12-31 451浏览

