以下内容来自腾讯工程师 lark
本文主要介绍了:
- Golang的语言特性,包括语言基本构成、数据类型、流程控制与并发处理等;
- 单元测试,包括单元测试的基本概念、单测框架、实际案例等
- 其他简单介绍了技术转型过程以及golang组件开发
语言基本构成
和所有的编程语言一样, Golang语言也是从词法元素开始,然后从数据类型开始,搭建起整个语言大厦。
Golang用于定义数据的语言设施有常量、变量、基本类型、容器类型、抽象数据类型、值类型与引用类型。
Golang不是面向对象的,它本质上是一种抽象数据类型(ADT),简单来说就是由数据及其操作构成了一个数据类型。
以下是一个总图,接下来的篇幅逐步展开介绍。

词法标记
token是go语言的词汇构成,golang的token可以分为四类:
- 标识符identifiers、
- 关键字 keywords、
- 运算符与标点符号operators and punctuation、
- 字面量literals

字面量
区别于C语言,“字面量”在 Go里面是一个非常重要的概念,用“字面量”来生成变量是最为便捷的方式。
用过Python的同学都知道,字面量是生成数据类型的非常便捷方法,例如在python里{“Name”:“Bob”, “Age”:23}生成一个dict,
在Golang里map[int][string]{1:"a",2:"b"}生成一个map。
用好字面量,能够写出简洁可读的代码。

变量
这部分主要包括变量的定义、类型判断、类型转换等。

常量
这部分主要包括常量的定义以及一些定义产量的例子。

以下是两个从trpcgo中截取的,用const和var关键字定义错误码的例子。

基础数据类型
标量类型
布尔、数值和字符串是Golang中基本的标量类型。

容器类型
数组、切片、Map构成了Golang中的容器类型。


抽象数据类型
本小节用抽象数据类型来囊括结构体、函数、方法和接口这四部分,这样做和大部分Golang教科书的讲法不同,之所以这样做,是因为对于有C/C++经验的同学可能更容易理解。
ADT一个比较形式化的定义:为类型的属性和可对类型执行的操作提供一个抽象的描述。不受特定的实现和编程语言的约束这种正式的抽象描述被称为抽象数据类型(AbstractDataTypeADT)
上面的定义比较长也比较抽象,简单理解的话,ADT=数据+操作

结构体
这部分总结了Golang中的结构体的定义,创建结构体变量的方法,以及结构体字面量的写法,Golang中的结构体基本上类似于C语言的结构体。

函数
函数是Go的核心概念之一,和结构体和接口一样,函数类型属于一等类型,这意味着可以定义函数类型、函数变量、将函数变量指向一个函数值、将函数变量作为返回值返回等。

匿名函数与闭包是Golang的核心概念之一,是平时的编程实践中频繁使用的功能之一。
掌握以下几点有助于掌握匿名函数与闭包:
- 闭包是磨名函数与匿名函数所引用环境的组合。
- 匿名函数有动态创建的特性,该特性使得匿名函数不用通过参数传递的方式,就可以直接引用外部的变量
- 匿名函数即函数类型的字面量
- 匿名函数,一定是出现在闭包里;也就是只能在函数体里面定义一个匿名函数

Golang的错误处理分为错误和异常,错误不像异常,因为错误没有什么特别之处,而未处理的异常可能导致程序崩溃。
Golang中的错误机制:
- 错误用error来表示,error是一个接口,程序有错误则返回error,无错误则返回nil。
- 异常处理机制通过panic和recover关键字来处理

Golang不是面向对象语言,整体上是一种“函数式”编程,以下是一些高频使用的内建函数,配合自定义类型使用,能够写出简洁的代码。

方法
定义一个结构体后,可以给这个结构定义相应的方法,用于对这个结构体进行各种操作。
以下是方法的声明与定义:

方法有接收器和方法集的概念,理解起来比较繁琐,实际的编程中,掌握以下一点就行:
- T还是*T?如果很难确定方法是否应该使用指针接收器还是值接收器,那么一般选择指针接收器(*)方式。


接口
Go接口是一组方法的集合,可以理解为抽象的类型。通过Go接口,可以实现面向对象语言中的多态,多态就是同一个接口,使用不同的实例而执行不同操作。
Go接口机制是非侵入性的,即无需在该类型上添加显示声明,go没有implements,extends这些显式的关键字,go的实现方案是一种鸭子类型:看起来像鸭子,那么它就是鸭子。任何类型,只要实现了该接口中方法集,那么就属于这个类型。

Go可以用空接口和类型断言来实现一种动态泛型(区别于基于模板的静态泛型),接口值可有包含各种不同的具体类型值,而类型断言就是用于从接口中动态的区分出各种具体的类型,从而可以使用具体的类型。
类型断言是在程序执行时进行,而不是在程序编译是进行的,因而是一种动态泛型。

以下是一个使用动态泛型的例子:

流程控制
判断
和C语言一样,使用if-else关键字做判断。

循环
Go中的循环通过for关键字实现,主要有以下几种使用方法:
- 类似C语言的形式,for i=0;i
- 迭代器形式,for-range,这是go中很强大的循环方法
- 条件形式,go语言没有while关键字,可以通过for的条件形式来模拟
- for也可以配合break和continue来使用

分支
整体上类似C语言的switch,一个特殊的场景是结合Go的反射使用type-switch做变量类型判断分支。

跳转
和C语言一样,有goto、break、continue三个关键字。

并发处理
goroutine
实际编程时,涉及到goroutine的地方,其实很简单,主要就以下3点:
- 创建go协程:在函数调用前面加一个关键字go就搞定
- 等待协程结束:平时的开发中一个典型场景是,一个前端请求过来,Svr启动若干个go协程去拉数据,等所有协程执行完数据全部拉取回来后,在Svr做业务逻辑。这部分通过WaitGroup来处理。
- 出错时取消其他协程:多个协程构成一个事务的场景,当其中某一个协程出错时,取消其它协程的执行,让整个事务处理提前结束,减少系统开销。这部分通过ErrGroup来处理。



Go语言的并发能力使用起来很简单,在函数调用前面加一个关键字go就搞定,但goroutine的底层实现非常复杂,以下简单介绍了一下Go调度器的内部实现原理。
现代的计算机体系结构大体上提供了3种并发机制:
- 编程语言层面的并发:例如Go语言中的goroutine
- 操作系统层面的并发:进程或线程并发模型
- CPU层面的并发:CPU的多个执行核
Go语言的并发是一种语言级的并发,Go 语言的并发是通过Goroutine调度器实现的,从Goroutine调度器的内部实现来看,它实际打通了【语言并发-OS并发-CPU多核】三层并发,是一种从软件到硬件的整体并发。


整个Go调度器还是非常复杂的,但我们可以抓住GPM结构模型和抢占式调度算法来做一整体理解:

context
本质上goroutine 都是平行调度使用,不存在goroutine '父子' 关系。
golang1.7引入context,用来跟踪 Goroutine 的调用, 在调用内部维护一个调用树
1)通过这个调用树可以在传递超时或者退出通知
2)还能在调用树中传递元数据

Context基本上是两类操作:
- 3 个函数用于限定什么时候你的子节点退出;
- 1 个函数用于设置请求范畴的变量

可以通过Context建立起超时链:

通过Context.Value传递告知性质的东西,而不是控制性质的东西:

channel
在Go语言中,channel配合select,提供了强大的并发能力。
对比Golang中的通信与异步处理结构,与我们熟悉的C++服务端编程常用的通信与异步处理结构,在结构上有一种相似性。

与channel相关的操作语法:

channel的底层实现,基本技术点可以总结如下:

select
与select相关的操作语法:

select的一些使用技巧,可以总结如下:

单元测试
在2020年转到golang之前,我们一直是C++开发,开发只做简单的接口测试或功能测试。转到golang之后,除了接口测试,最大的变化的就是有了单元测试。在用C++做开发的时候,通常都是整个代码写完后,然后编译、调试、测试,粒度是整个模块级的,主要是功能一级或接口一级的测试;转到Golang之后,在之前流程的基础上,新增了单元测试,在写单测的过程中,慢慢体会到了写单测带来的好处。

对比C++开发和Golang开发,并不是说C++不能写单元测试,也不是说开发同学的认知突然有了飞跃,一夜之间认识到了单元测试的好处然后行到起来,而是说Golang语言及其完善的工具链,让写单元测试变成一件非常简单的事。在单元测试这个事情上,是实践改变了认知,而不是认知改变了实践。
想象一下,每当自己写完后几个函数后,给每个函数配上单测,然后runtest,然后函数跑通,每每这时,都能体会到自己的代码跑起来的那种激动。如果没有单元测试,这种激动则要等到整个模块写完,在做功能测试或接口测试的时候才会有,在这之前很长一段时间里,在代码没跑起来的时候,总是伴随有一种不安感。我不知道,是不是每个写代码的人,都有这种感觉。

以下介绍一些Golang单元测试相关的技术。
关于单测



单测框架




几个例子
下面列举几个我们工作中单测的例子。



几个Golang在线学习网站:
Go官网:a href="https://golhttp://ang.org/"> https://golang.org/
Go语言中文网:
https://studygolang.com/
Go入门指南:
https://github.com/Unknwon/the-way-to-go_ZH_CN
href="https://github.com/Unknwon/the-way-to-go_ZH_CN">Go 语言圣经:
https://www.bookstack.cn/books/gopl-zh-simple
href="https://www.bookstack.cn/books/gopl-zh-simple">Go 语言原本(技术内幕)
https://changkun.de/golang/
欢迎点赞分享,搜索关注【鹅厂架构师】公众号,一起探索更多业界领先产品技术。
文章来源于互联网:<a%20href="https://zhuanlan.zhihu.com/p/629812048" target="_blank" rel="noopener">聊聊Golang:语言特性、单元测试、组件开发