1、初识Go

Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功用的编程言语。

Go与java、.net这些OOP语言有哪些不同。
不太记得是哪一年传闻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、比起其它言语有什么独特的魅力

运行机制:

  1. go编译出来的是二进制机器码的程序。
  2. 不需求安装runtime(.net、java、python需求特定运行环境)
  3. 没有JIT带来初次访问慢的问题,go归于AOT
  4. go与大部份OOP言语相同,带GC功用,咱们不需求手动开释内存。
  5. 编译出来的运用占用空间十分小
  6. docker能够运用alpine:latest镜像

代码层面:

  1. 语法超级简略,没有复杂的各种类型。
  2. 支撑interface,更主要的完成类不需求显现的依赖接口
  3. 比多线程愈加轻量级的用户态协程,一个协程只占用2KB栈空间
  4. 敞开一个异步(协程)只需求在调用时,加go关键字。
  5. 通道channel,是其它言语没有的先天优势。搭配select运用,超级舒服。
  6. 与大多数OOP言语相同也有泛型(可惜不支撑办法泛型,支撑结构体泛型函数泛型)。
  7. 支撑多个回来值(大多数言语只支撑1个以内)
  8. 打开一个go的项目代码看起来像脚本相同轻巧,没有程序集、jar包、子模块的粗笨加载进程。
  9. 不需求maven、nuget,能够直接引证github的第三方包
  10. 运用指针来操控一个目标运用引证类型、仍是值类型。

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的引证作用,用指针即可)。

SetLeaderActivate 是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的同学,有一个大约的了解。

期望对咱们有帮助。