使用Go已有两个月,Go给我的印像就是简单。社会很复杂,但Go很简单。谈不上喜欢Go,但也不抵触。Go已经成为我的第二门语言,也会帮助我在云原生方向的深入学习。
Go语法简单,代码格式很统一,空格都是约定的,用Go写出来的代码整洁,不会出现千人千面,除非代码能力真的很烂。对于有强迫症的我,都不需要格式化代码了。
但Go没有继承,即便可以用匿名字段实现继承父类,也需要显示调用父类方法。对于需要初始化的父类,父类必须提供初始化方法由子类调用。加上Go缺少泛型,使得很多代码无法复用,导致项目中出现非常多的冗余代码。
Go实现接口无需使用关键字,但是少实现一个方法也是不算实现接口的,编译也不会报错提示。很多时候,由于接口新增一个方法或者修改方法签名,没有提示很容易忘记修改实现类。
使用Go需要严重依赖开发工具,如果没有IDE,我们根本看不出来,一个类实现了哪些接口,但这也算不上缺点,毕竟我们也不可能离开IDE用纯文本工具开发与阅读源码。
Go支持方法传递,简化了回调的实现,不需要先创建接口那么麻烦。Go支持多返回值,很多时候都不需要像Java那样先创建一个用于包装返回值的类,当然,如果返回值具有共性,应封装为结构体。
Go提供协程,弱化了线程的概念,也弱化了线程池的概念,执行一个异步方法更加方便了。但这也导致go func分布在各个角落,很难想象一个go项目会创建多少个协程,以及这些协程的生命周期。
Go协程也是运行在线程上的,当一个协程发生阻塞时,也必然是有一个线程不能使用,如果很多的协程发生IO阻塞,也会有创建出非常多的线程,也会消耗内存资源,所以使用协程时也不能无脑创建协程,能用一个协程处理的,不要创建一堆协程。
Go语法说简单也复杂,chan、map这些默认是指针传递,而结构体如果不显示声明指针传递,那么就是值传递。结构体哪些字段需要声明为指针类型,哪些字段需要手动初始化,什么时候应该使用指针,都容易让初学者找不着北。
Go约定返回错误信息,而不是抛出异常,如果抛异常,调用链深的情况下就很容易忘记处理异常,导致进程退出。总不能每个方法都实现一下捕获异常,所以我们会写非常多的if err!=null的代码,有时一个方法10行代码6行都是处理err的代码。
Go中协程之间数据传递一般用chan,一般I/O阻塞方法都是返回一个chan,调用方通过
select {
case <-chan:
// do
case <-time.After(超时时间):
// do
}
语法,也可实现当chan阻塞超时时,能够跳出阻塞。
Go模块化有好也有不好的地方,每个Modlue都可以有一个init方法,在这个Modlue被使用时调用,这能够让Modlue有很好的封装。不好的地方就是容易被乱用,导致接手项目时很难找出应用启动的主流程。
由于我们只用Go写基础服务,所以写业务项目这方面就不与Java对比了。总之,Go没有Java功能强大,但Go有着接近C的性能,也有Java的垃圾回收功能,有着简单语法,不需要了解太多线程知识也能写出高性能的应用。