1、初识Go
Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功用的编程言语。 不太记得是哪一年传闻go这门言语了,横竖有好多年了,Google出品的即便不学也得了解,由于我对各种编程言语的重视还算是比较感兴趣,当然我也并没有去深化学习,仅仅略微了解作为自己的知识广度。
记得在2017年左右,原公司的一个API服务便是用GO来重写的,QPS大约在1-2万左右,算是公司的第一个用GO来写的体系了。那时分全公司有200个体系左右,机器在5千台左右(还没推行一机一应的战略)。公司大部份是.NET、JAVA以及少数的PYTHON(运维部分、DEVOPS)在用。
由于身边有了用GO写的事例,所以让我愈加重视这门言语,也因而买了一本纸质书,由于作业忙一直没有静下心来翻阅学习,直到在2022年上海疫情只能留在家里,所以我下定决心开端研讨GO。
2、GO能做什么
咱们要了解一门言语之前都会有这个疑问:这门言语能做什么
、比起其它言语有什么独特的魅力
、谁在用,生态怎么
、功用怎么样
?
能够做:客户端运用、web运用,至于移动端APP、带UI的客户端,这两个我没有触摸,在这儿不做描述。
还包含像一些分布式运用
(比如ETCD)、网关
(Traefik)、云原生平台的二次开发
(这个招聘岗位不少)区块链
(这个招聘岗位不少)
当然像K8S、Docker这两个就不必多说了。
3、比起其它言语有什么独特的魅力
运行机制:
- go编译出来的是
二进制机器码
的程序。 -
不需求安装runtime
(.net、java、python需求特定运行环境) - 没有JIT带来初次访问慢的问题,go归于
AOT
。 - go与大部份OOP言语相同,
带GC功用
,咱们不需求手动开释内存。 - 编译出来的运用
占用空间十分小
。 - docker能够运用
alpine:latest镜像
代码层面:
-
语法超级简略
,没有复杂的各种类型。 -
支撑interface
,更主要的完成类不需求显现的依赖接口
。 - 比多线程愈加轻量级的
用户态协程
,一个协程只占用2KB栈空间
。 - 敞开一个异步(协程)只需求在调用时,加
go
关键字。 -
通道channel
,是其它言语没有的先天优势。搭配select运用,超级舒服。 - 与大多数OOP言语相同也有
泛型
(可惜不支撑办法泛型
,支撑结构体泛型
、函数泛型
)。 - 支撑
多个回来值
(大多数言语只支撑1个以内) - 打开一个go的项目代码看起来像脚本相同轻巧,没有程序集、jar包、子模块的粗笨加载进程。
- 不需求maven、nuget,能够
直接引证github的第三方包
- 运用
指针
来操控一个目标运用引证类型、仍是值类型。
4、谁在用,生态怎么
go的明星产品有许多,像K8s、docker这些咱们几乎都会运用到。(我是从traefik开端下定决心来学习GO的)
更主要的是,我从招聘岗位调查,几乎国内的头部公司都在用,而且越来越多。
可惜现在还没有一个十分老练而且比较威望的框架,这一点java的做的真不错。
别的,转GO方向的,有许多是来自PHP、C++的开发人群。
一款言语值不值得学,看商场、看岗位。这个咱们能够先去看下现在go的招聘岗位数量、头部互联网公司的招聘。
5、开发功率、功用怎么
从我的运用感受来说(不威望),尽管GO宣扬编译很快,应该是对标C++来说,编译速度很快。可是我感觉没有想象中的快,而且仍是有点慢。
得益于GO是AOT形式
,没有just in time的那种初次访问慢的问题,这个是我喜爱GO的原因之一,许多时分需求做持续部署,像其他言语的JIT形式导致每次发布后,都要自己去跑一下一切接口的恳求。不然初次访问会让下流体系出现超时报警的反常。
尽管go不支撑lambda、linq,无法很优雅的完成对一个调集的挑选聚合操作。可是GO在全体开发功率上,我感觉比.NET/JAVA的开发功率要更高些
。假如做一个项目
时让我挑选言语的话,我应该会首选GO
。
GO对CPU密集型的操作没有.NET CORE快,这一点等我有时刻出一个对比测验。
用GO写出一个异步调用、多线程运用,应该没有其它言语有像GO相同简略了。这也是为什么GO如此优秀,不需求咱们把握多复杂的多线程技术、考虑各种互斥条件,就能写出QPS足够高的运用了。
其他言语的async await是很不错,但会破坏全体的结构(保证一切的下层都要运用async),一起要提供同步版别、异步版别。这在GO中是不存在的,由于要不要运用异步,由调用方决议,不需求完成方设定。
6、GO的Hello World
package main
import "fmt"
func main() {
fmt.Println("Hello World go!")
}
- package:当时包名(或者命名空间)
- import:导入其它包(引证其它完成好的包),这儿也能够是直接引证github地址的包
便是让咱们有个直观的认识,不做详细的代码解说。
7、GO的类目标
事实上GO没有class
的,只要结构体:
package serverNode
import (
"github.com/farseer-go/fs"
"github.com/farseer-go/fs/configure"
"github.com/farseer-go/fs/parse"
"strings"
"time"
)
type DomainObject struct {
Id int64 // 客户端ID
Name string // 客户端称号
Ip string // 客户端IP
Port int // 客户端端口
IsLeader bool // 是否为Master
ActivateAt time.Time // 活动时刻
}
// SetLeader 设为master
func (receiver *DomainObject) SetLeader(leaderId int64) {
receiver.IsLeader = leaderId == receiver.Id
}
// Activate 更新活泼时刻
func (receiver *DomainObject) Activate() {
receiver.ActivateAt = time.Now()
}
import 这儿导入了来自github的开源框架
。
DomainObject
是一个结构体ValueType,没有class类型
(要完成class的引证作用,用指针即可)。
SetLeader
、Activate
是DomainObject的办法(Method)
。
咱们知道OOP中的类一般有:字段、特点、办法、虚办法、承继。GO在这儿只要字段、办法。能够经过匿名字段完成承继的目地。
8、与其他OOP言语的差异
- GO没有类(class),有struct(结构体),能够经过指针来操控引证或值类型。
- GO没有抽象类。
- GO不支撑虚办法。
- GO没有特点,只要字段、办法。(OOP一般会有字段、特点、办法)
- GO是经过命名规矩来界说public、private的。(大写是public、小写为private)
- GO没有构造函数和析构函数。
- GO没有承继,不过结构体中的匿名字段能够到达相同的作用。
- GO不支撑像类、办法的注解、特性,不过GO支撑字段的注解。
- GO实例化一个目标时不需求NEW关键词。一般是:结构体称号{}
- GO的struct要完成一个接口时,不需求显现申明,只需求完成这个接口的一切办法即可。
- GO不支撑办法重载。
- GO有函数、办法的区分。函数是指没有struct的独立“办法”,而办法便是指struct内部的办法。
- GO的函数能够界说成一个变量类型,做为其它办法、函数的出入参。
- GO的出参支撑多个。(在OOP中,多个出参不得不界说一个类出来)
- GO没有办法入参的默认参数设置。
- 办法入参的界说中,变量称号在前、变量类型在后。
- GO的字符串拼接不支撑插值办法,一般运用format办法。
- GO没有null的概念(有nil),除了指针、map、切片、channel,都会有默认值。
- GO不支撑运算符重载。
- GO没有多线程的概念,可是能够经过GO关键词完成异步(协程)调用。
- GO有一个Channel通道,用于异步调用时的收发音讯。
- 其它言语要完成select channel的作用,最起码多出10几行的代码,而且功用远没有GO好。
- 不支撑扩展办法。这个其实蛮难受的,不过习气了也还好。
- GO没有枚举类型。
- GO没有try catch机制。(不过能够自己完成)
- GO无法经过反射查找当时包(程序集)下有哪些界说的struct。
- GO的调集只要数组、切片、Map字典三种类型。
9、有必要学习GO吗
就我运用下来,我觉得仍是蛮有必要的,它的语法精简、高效的开发功率、轻巧的开发体会、AOT的编译形式、极小的本钱完成并发、带GC、编译的程序体积小、而且许多优秀的中间件也是GO写出来的。
这些长处我想足以招引你去学习了解这门言语了。
10、学习GO的曲线
GO相对其他言语来说十分简略,由于GO内置的语法十分精简,大约只要25个关键字
左右。假如你有其它编程言语的经历,需求了解这些语法大约只需求几个小时(初步认识这些关键字作用)
我学习的时分习气看纸质书,大约看了10天左右(期间没有写过一行代码)。在第11天就着手开端写GO的框架。
由于我在其他言语都会有自己的一套框架,所以在看完书入门了之后,就开端用GO来完成框架。
有一点值得注意的是,切片、协程、通道在其它言语上很少见到,所以要真实的理解到位,仍是得花上一点时刻来研讨,毕竟这是一个新大陆,能为你敞开新的编程思想。
别的,学习一门新的言语,咱们除了把握根底语法
、了解言语的特性外,还得先研讨有哪些流行的根底框架
,然后学习各个根底框架的根底用法。比如数据库、redis、es、etcd、eventBus、mapper、行列等等。
在这儿,共享一个我开源的框架,完成了咱们开发中运用到的大部份根底框架。
farseer-go 运用文档
11、随处可见的any类型
为什么要运用any类型?any相当于oop中的object类型。
由于go不支撑办法泛型
(只支撑函数、结构、接口),导致当结构体确定时,要回来不同的“动态”类型时,只能运用any。
// Sum 求总和
func (receiver Enumerable[T]) Sum(fn func(item T) any) any {
lst := *receiver.source
var sum any
for index := 0; index < len(lst); index++ {
sum = Addition(sum, fn(lst[index]))
}
return sum
}
这段代码的入参fn是一个函数变量,fn的回来值,以及Sum办法的回来值都是any类型。
假如支撑办法的泛型,这个any就能够是int、float这种数字类型,调用时也不需求再做一层转换了。
12、随处可见的error类型
GO不支撑try catch机制,GO引荐运用error机制来回来这个过错类型,由上层判别。
// StringSet 设置缓存
func (redisString *redisString) StringSet(key string, value any) error {
return redisString.rdb.Set(fs.Context, key, value, 0).Err()
}
比如这块的redis操作。StringSet,其间有可能发生网络IO过错,这时是不会抛出反常的,而由上层调用根据error!=nil来判别是否有反常。
13、能运用OOP的IOC、AOP思想吗
关于一些GO开发者来说,一看到这就会吐槽,肯定会说既然用GO,就不要用JAVA那一套了。 难道AOP、IOC = JAVA吗?所以我很不认同这些观点。
关于依赖运用AOP、IOC的小伙伴们,必定是为了将业务与技术完成之间做一个解耦。 举个比如,在一个函数中需求打印日志、埋点、业务,或者敞开某个功用。仔细想想这些是不是业务逻辑呢?
习气了面向目标编程的小伙伴们,肯定会离不开IOC(就像我)。由于咱们习气面向接口编程,就像设计准则中提到的相同。而在GO中运用IOC是完全能够的。
当然原生的规范库中没有IOC框架,不过我自己有完成这个包,感觉兴趣的小伙伴能够在github上看我共享的开源框架。
farseer-go 运用文档
AOP也是能够支撑的,咱们知道AOP有两种完成机制:
- 静态植入
- 动态代理
GO在编程的进程中,首要会将咱们写的代码转成语法树AST。而这个AST就能够让咱们做一个静态植入。 不过现在我还没有花时刻去研讨这个小领域。
14、select case
通道是其他言语所不具备的原生能力。 channel相当于一个本地行列,能够往这个行列发送音讯,一起也能够往这个行列读取音讯。一般运用于协程(多线程)。
举个比如: 有一个60S的使命,假如期间有数据需求更新,则先更新数据,然后从头计时60S。
for {
select {
case <- time.After(60 * time.Second).C: // 倒计时60S
// 60S时刻到了 doing job
case <-receiver.updated: // 等待数据更新的动作
// 有数据进来,需求先更新
}
}
在GO中完成这个需求,十分简略,使用select case(与switch case有本质差异)。 在这段代码中,更能体现咱们人的思想办法。时刻倒计时与有数据更新的动作,是两个并行的逻辑,谁先满足就先履行谁。
这儿不去解说这些言语的关键字。小伙伴们想想假如用自己拿手的言语,完成起来需求几行代码。(当两个条件还没有满足时,这个时分程序是阻塞状态)
15、最终
本篇不是为了让咱们学习GO,仅仅帮助之前没有触摸过GO的同学,有一个大约的了解。
期望对咱们有帮助。