如有任何问题或建议,欢迎及时交流和碰撞。个人公众号是 【脑子进煎鱼了】,GitHub 地址: https://github.com/eddycjy 。
你们好,我是煎鱼。git
在 Go 语言中,一提函数,你们提的最多的就是 “Go 语言的函数是一等公民”。这个定义来的很是忽然,咱们先了解一下什么是一等公民。github
根据维基百科的一等公民(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 [函数名](入参)(出参)
,以下:app
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 + y return }
在出参时所声明的变量名称,是能够应用到自身函数的。所以若直接执行 return
则会隐式返回已经声明的出参变量。spa
在函数定义时,其入参还支持可变参数的语法:
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 语言的常规使用,数量很是少。以下:
针对每一个内置函数的真实使用场景,咱们会在后续的章节再进一步展开,由于每一个内置函数本质上都对应着各种型的使用场景。
在本章节中,咱们介绍了 Go 语言的函数为何称是一等公民,而且针对函数的各种变形:普通函数、匿名函数、结构方法、内置函数进行了基本的说明。
面对新手入门最容易犯错的函数做用域问题,也进行了基本的梳理。这块建议你们要多多深刻思考、理解,避免往后踩坑。
分享 Go 语言、微服务架构和奇怪的系统设计,欢迎你们关注个人公众号和我进行交流和沟通。
最好的关系是互相成就,各位的点赞就是煎鱼创做的最大动力,感谢支持。