Go语言入门——函数
写了快一个月的Go,已经没有什么陌生感了。
一行代码写完,不会在行尾本能的敲上“;”,直接Enter键换行;
定义变量把变量名放在前面,类型放在后面;
使用struct去定义自己想要的数据模型就好比定义一个Java中的model一样……
这些不用可以经过大脑加工思考,就想自己还在写Java一样。
还记得当时在看《Go实战》的时候看到变量类型后置的声明方式,我还在极力吐槽这种不人性的语法,如果我已经站在了真香的队伍里,和其他的真香同学别无二致。
感慨,人的适应能力真的强👍
作为一个Java重度爱好者,其实在每次写Go的时候都会情不自禁的把两者进行对比,在写文章的时候也会经常提到。当然了,今天主要说的还是Go的函数。
1、Go语言中的函数长啥样
func f(a int, b int) (ret int, err error) { fmt.Println("This is function") return }
没错,这大概就是一个典型的Go风格的函数,那么它有哪些特色
- 入参
- 返回值
2、入参
2.1 参数合并声明
入参的变量也是变量后置的,这里a变量和b变量是相同类型的,所以也可以写成
a, b int
对于不同类型的参数需要分开定义。
2.2 不定参数
除此以外,入参还支持不定参数
比如可以这样定义
func f(args ...int) { for _, arg := range args { fmt.Println(arg) } }
针对不定参数的函数,我们可以这样调用
f(1)
f(1, 2)
f(1, 2, 3)
避免了我们在函数里定义一长串变量的情况。
上面的不定参数是int类型的,那么是否支持多种类型混用的不定参数呢?
是可以的,使用...interface{}这种形式
func f(args ...interface{}) { for _, arg := range args { switch arg.(type) { case int: fmt.Println("It is int type") case string: fmt.Println("It is string type") case int64: fmt.Println("It is int64 type") } } }
注意,这里的i.(T)形式不是强制转换或者隐式类型转换,这是类型断言,表示判定类型的。
Go里面是没有隐式类型转换的,不仅没有,而且强制类型转换也很严格。
3、返回值
3.1 返回参数
不同于Java,Go函数是可以支持多返回值的,比如这里返回了ret和err两个参数。
返回值的定义方式也很灵活,可以写成
func f(a int, b int) (int, error) { fmt.Println("This is function") return }
如果返回只有一个参数可以写成
func f(a int, b int) (ret int) { fmt.Println("This is function") return }
或者
func f(a int, b int) int { fmt.Println("This is function") return }
3.2 “_”的用法
在前面的文章,我们也顺带提过,对于函数返回的值,有些我们不关心或者不需要的话,我们不能抹掉他的位置,但是可以使用"_"来表示这个参数的存在,只是不用而已,比如这样调用上面的函数是不行的
ret := f(1, 2) // 缺少err返回值
但是这样是OK的
ret, _ := f(1, 2)
或者这样
_, err := f(1, 2)
3.3 error
error接口是Go标准库为了错误处理提供的接口。
一般在业务代码中,我们会调用某个方法后,判定方法对应的值是否为nil判定方法是否被正常执行
if err != nil { // 没有正常执行 } else { // 正常执行 }
3.4 panic和recover和defer
说到error,正好说说panic()和recover()两个函数
当我们遇到一些err的时候,我们可能就会直接抛出panic,这里的panic可以近似理解为Java里面的Exception,即抛出异常。
if err != nil { panic(err) }
一旦抛出panic,则程序将会终止,除非遇到一种情况,即有recover的存在。
说到recover则不得不提defer
defer是Go里面的新特性,有点类型Java里面的finally,承担回收资源或者解锁这类的收尾工作,但是比finally要灵活,Go函数的defer可以放在函数的任意位置,不管函数是否正常执行,在跳出函数前都会执行defer定义的函数。
接着说recover,如果在函数抛出panic,只要在最后遇到recover也是可以恢复正常的,形式如下
defer func() { if ret := recover(); ret != nil { fmt.Println("Catch Runtime Error:) } }
4、其他
4.1 说说func
每个函数都以func开始,来表明自己是一个函数。
那么学过Java的肯定会问,没有像public、private这样的访问修饰符吗?
没有,但是Go通过另外一种规则实现了访问范围即可见性。对于函数名使用大写字母开头,则表示可以被其他包使用,如果使用小写字母开头,则只能本包内使用。
当然,这个规则,也适用于变量的声明。
4.2 匿名函数
和Java等其他语言一样,Go函数也有匿名函数。
func (a, b int, s string) int { ... }
可以通过直接在后面赋值的方式直接执行
func (a, b int, s string) int { ... }(1, 2, "test")
这里主要从Go语言的函数构成包括关键字func,入参和返回值介绍Go函数的一些特性。当然了,Go函数还有很多灵活性就不再一一阐述了,有待你我在业务项目中慢慢实践体会了。
5、技术沙龙
今天去参加了一个技术沙龙,主题是数据存储与微服务架构实践方面的。
这是自己第一次除了参加公司组织的各种会议以外,自己主动报名的线下技术沙龙。
会上听到了阿里、百度的大佬分享关于过去的技术沉淀和对未来技术方向的展望,整体还是蛮有收获的。
拓宽了自己的知识面,也加深了对一些框架或者工具的理解,比如ServiceMesh。之前对于ServiceMesh的理解仅限于阅读各种文章,自己的理解也比较有限,这次通过阿里大佬的解释,更加清晰的了解了ServiceMesh以及它的优势。
最后晒一下在回答问题环节,主办方送的马克杯,好评
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。