Go 语言中的一等公民:看似普通的函数,凭什么?
大家好,我是煎鱼。
在 Go 语言中,一提函数,大家提的最多的就是 “Go 语言的函数是一等公民”。这个定义来的非常突然,我们先了解一下什么是一等公民,他又凭什么?
根据维基百科的一等公民(First-class citizen)的定义:
In programming language design, a first-class citizen (also type, object, entity, or value) in a given programming language is an entity which supports all the operations generally available to other entities. These operations typically include being passed as an argument, returned from a function, modified, and assigned to a variable.
在编程语言设计中,给定编程语言中的一等公民(也就是类型,对象,实体或值)可以把函数赋值给变量,也可以把函数作为其它函数的参数或者返回值来直接使用。
Go 语言的函数也满足这个定义,因此常被称为 “一等公民”,非常有意思。了解清楚背景后,接下来进一步展开。
普通函数
在 Go 语言中普通函数的定义格式为 func [函数名](入参)(出参)
,如下:
func callFuncA(x, y string) (s string, err error) {return x + y, nil
}func main() {callFuncA("炸", "煎鱼")
}
在示例代码中声明了一个函数名为 callFuncA
的方法,他只允许在包内调用,因此首字母为小写。
其具有两个入参,分别是 x
和 y
,类型都为 string
。而出参为变量 s
和 err
,类型分别为 string
和 error
。
另外在函数体内返回值时,也可以采用快捷返回的方式:
func callFuncA(x, y string) (s string, err error) {s = x + yreturn
}
在出参时所声明的变量名称,是可以应用到自身函数的。因此若直接执行 return
则会隐式返回已经声明的出参变量。
在函数定义时,其入参还支持可变参数的语法:
func callFuncA(x ...string) (s string, err error) {s = strings.Join(x, ",")return
}func main() {fmt.Println(callFuncA("炸", "煎鱼"))
}
在入参变量上声明为 x ...string
,则表示变量 x
是 string
类型的可变变量,能够在入参时传入多个 string
参数。
可变变量所传入的格式为切片(slice)类型,该类型我们会在后面的章节进行讲解,你可以理解为不受长度限制的动态数组:
[0: 炸 1: 煎鱼]
一般对可变变量的常见后续操作多是循环遍历处理,又或是进行拼接等操作。
匿名函数
Go 语言也默认支持匿名函数的声明,声明的方式与普通函数几乎一样:
func main() {s := func(x, y string) (s string, err error) {return x + y, nil}s("炸", "煎鱼")
}
匿名函数可以在任意地方声明,且不需要定义函数名,如果在函数体后马上跟 ()
则表示声明后立即执行:
func main() {s, _ := func(x, y string) (s string, err error) {return x + y, nil}("炸", "煎鱼")
}
而在所有的函数类使用中,有一点非常重要,那就是函数变量作用域的理解:
func main() {x, y := "炸", "煎鱼"s, _ := func() (s string, err error) {return x + y, nil}()fmt.Println(s)
}
该匿名函数没有形参,函数内部没有定义相应的变量,此时其读取的是全局的 x
、y
变量的值,输出结果是 “炸煎鱼”。
func main() {x, y := "炸", "煎鱼"_, _ = func(x, y string) (s string, err error) {x = "吃"return x + y, nil}(x, y)fmt.Println(x, y)
}
该匿名函数有形参,但是在函数内部又重新赋值了变量 x
。那么最终外部所输出的变量 x
的值是什么呢?输出结果是 “炸 煎鱼”。
为什么明明在函数内已经对变量 x
重新赋值,却依然没有改变全局变量 x
的值呢?
其本质原因是作用域不同,函数内部所修改的变量 x
是函数内的局部变量。而外部的是全局的变量,所归属的作用域不同。
结构方法
在结合结构体(struct)的方式下,可以声明归属于该结构体下的方法:
type T struct{}func NewT() *T {return &T{}
}func (t *T) callFuncA(x, y string) (s string, err error) {return x + y, nil
}func main() {NewT().callFuncA("炸", "煎鱼")
}
具体的函数的使用方法与普通函数一样,无其他区别。
而与结构体有关的值传递、引用传递的方法调用将在具体后面的章节再展开。
内置函数
Go 语言本身有支持一些内置函数,这些内置函数的调用不需要引用第三方标准库。内置函数的作用是用于配合 Go 语言的常规使用,数量非常少。如下:
用于获取某些类型的长度和容量:len、cap。
用于创建并分配某些类型的内存:new、make。
用于错误处理机制(异常恐慌、异常捕获):panic、recover。
用于复制和新增切片(slice):copy、append。
用于简单输出信息:print、println。
用于处理复数:complex、real、imag。
针对每个内置函数的真实使用场景,我们会在后续的章节再进一步展开,因为每个内置函数本质上都对应着各类型的使用场景。
总结
在本章节中,我们介绍了 Go 语言的函数为什么称是一等公民,并且针对函数的各类变形:普通函数、匿名函数、结构方法、内置函数进行了基本的说明。
面对新手入门最容易犯错的函数作用域问题,也进行了基本的梳理。这块建议大家要多多深入思考、理解,避免日后踩坑。
关注煎鱼公众号,吸取精华:
???? 点击关注煎鱼,在知识的海洋里遨游
学习资料分享,关注公众号回复指令:
回复【000】,下载 LeetCode 题解大全。
回复【001】,下载 Go 进阶图书 Mastering Go。
Go 语言中的一等公民:看似普通的函数,凭什么?相关推荐
- Go语言系列——31-自定义错误、32-panic和recover、33-函数是一等公民(头等函数)、34-反射、35-读取文件、36-写入文件
文章目录 31-自定义错误 使用 New 函数创建自定义错误 使用 Errorf 给错误添加更多信息 使用结构体类型和字段提供错误的更多信息 使用结构体类型的方法来提供错误的更多信息 32-panic ...
- 作为一等公民的 Python 函数
文章目录 参考 描述 一等公民 概念 Python 中的一等公民 一切皆对象 人人平等 作为一等公民的 Python 函数 作为函数的参数进行传递 作为函数的返回值进行返回 作为数据结构中的元素 能够 ...
- c语言 字符串 strncpy,详解c语言中的 strcpy和strncpy字符串函数使用
详解c语言中的 strcpy和strncpy字符串函数使用 strcpy 和strcnpy函数--字符串复制函数. 1.strcpy函数 函数原型:char *strcpy(char *dst,cha ...
- 在C语言中以编程的方式获取函数名
在C语言中以编程的方式获取函数名 仅仅为了获取函数名,就在函数体中嵌入硬编码的字符串,这种方法单调乏味还易导致错误,不如看一下怎样使用新的C99特性,在程序运行时获取函数名吧. 对象反射库.调试工具及 ...
- 关于linuxC语言中创建进程,利用execlp函数执行.c程序问题
关于linuxC语言中创建进程,利用execlp函数执行.c程序问题 对于一个小白来说,这个系统调用真的太难了,完全摸不着头脑啊,一搜execlp函数,全是执行的命令,什么传参硬是没懂. 不过说到底, ...
- C语言中的二等公民在C++是如何翻身的?
在原来的C语言中,enum.const.auto等关键字都不尽完善,并没有发挥应有的功能,是二等公民,而随着时间的推移,在C++中他们都被完善了,有些还被赋予了新的功能,担当起了重要的角色.相反,原本 ...
- python 一等公民_Python中的一等公民
一流公民是指能够为促进其他同伴实体的所有运营提供支持的实体. 这些实体经常使用:在传递参数时,从函数中返回值,条件修改和值赋值. 在本文中,我们将研究Python 3.x或更早版本中一流公民的实现和使 ...
- c语言中用于获取字符串长度的函数是,C语言中求字符串长度的函数的几种实现方法...
C语言中求字符串长度的函数的几种实现方法 1.最常用的方法是创建一个计数器,判断是否遇到'\0',不是'\0'指针就往后加一. int my_strlen(const char *str) { ass ...
- R语言中的异常处理和eval函数
异常处理tryCatch() [R]R语言里的异常处理与错误控制 看看下面这个例子就能快速了解. #这里不要用c(1,2,'a',4), 因为R中向量中的元素必须一致,会自动转换成c("1& ...
最新文章
- evans pde 第三章_智慧树报关实务第三章答案
- 【JS】逻辑运算符 非! 与 或||(处理对象时注意)
- ipsec *** 的总结性谈论
- android 视网膜黄斑检查 amsler,自测黄斑病变 | 一张图搞定
- 免费发布一个简单而有趣的计算工具
- mybatis-plus实现乐观锁
- 【Vue】基础入门 —— 黑马程序员
- Android SDK ADB命令行总结
- Android 炫酷自定义 View - 剑气加载
- 以核心素养为导向的计算机教学方式,核心素养导向的课堂教学-感悟
- PhoneWindowManager().interceptKeyBeforeQueueing()中的interactive变量值的来源
- 深度学习+语音,基础普及篇笔记(一)
- 【MQTT基础篇(五)】发布、订阅和取消订阅
- 奥特曼宇宙英雄服务器维修,奥特曼宇宙英雄1.1.7版本
- SQL Server 重新组织生成索引
- 以太坊(Ethereum) - 网络节点
- 经典C语言程序设计100例,部分有个人注解
- 地平线【OpenExplorer天工开物】开发平台
- 四川大学计算机导论吴承恩,四川大学计算机导论期末例题
- 一款好看的iapp捐赠榜单源码
热门文章
- 使用Piwigo管理您的照片
- 宏基笔记本预装软件中英文对照表
- android布局黑色字体颜色,Android 沉浸式状态栏-字体颜色与背景颜色修改实现与兼容...
- [Mac]苹果系统安装burpsuite 2.0.11
- ssm框架的企业固定资产管理系统
- C#学习1.string与StringBuilder
- CAD看图软件如何画线?
- 华为认证考试需要准备什么
- Scratch(三十四):古诗大作战
- PAT甲级A1013. Battle Over Cities (25)