Go 语言简介、编程规范与零散知识点
Go 语言简介
Go 语言的历史
Go 1.5 版本 :2015 年 8 月发布,具有历史性意义。完全移除了 C 语言部分,实现了用 Go 编译 Go,仅少量代码使用汇编实现。同时,谷歌邀请内存管理专家 Rick Hudson 重新设计 GC,支持并发 GC,解决了 GC 时延(STW)问题。到 Go 1.8 时,GC 时延已从 Go 1.1 的数秒控制在 1ms 以内。
语言特性与版本兼容
在 Go 语言的版本迭代中,语言特性基本维持在 Go 1.1 基准上,官方承诺新版本对老版本开发的代码完全兼容。 Go 开发团队在新增语言特性上十分谨慎,而在稳定性、编译速度、执行效率以及 GC 性能等方面持续优化。
谷歌工程师的 20% 时间
谷歌的 “20% 时间” 工作方式允许工程师拿出 20% 的时间研究自己喜欢的项目,Go 语言最初便是这一工作方式的产物。
Go 语言优势
高效的并发编程 :通过 goroutine 和 channel 提供原生的并发编程支持。内存安全 :自动垃圾回收机制有效管理内存,减少内存泄漏和段错误问题。快速编译和部署 :编译速度快,可快速构建和部署应用程序。强大的标准库 :涵盖网络编程、并发控制、加密解密、文件操作等各方面功能和工具。
Go 语言特性总结
规范的语法 :不需要符号表来解析。垃圾回收 :独有垃圾回收机制。无头文件 。明确的依赖 。无循环依赖 。常量只能是数字 。int 和 int32 是两种类型 。字母大小写设置可见性 。任何类型都有方法 。没有子类型继承 。包级别初始化以及明确的初始化顺序 。文件被编译到一个包里 。没有数值类型转换 。接口隐式实现 。嵌入 :不会提升到超类。方法按照函数声明 。方法即函数 。接口只有方法 。方法通过名字匹配 。没有构造函数和析构函数 。postincrement(如 ++i)是状态 。没有 preincrement (i++) 和 predecrement 。赋值不是表达式 。明确赋值和函数调用中的计算顺序 。没有指针运算 。内存一直以零值初始化 。局部变量取值合法 。方法中没有 “this” 。分段的堆栈 。没有静态和其它类型的注释 。没有模板 。内建 string、slice 和 map 。数组边界检查 。
Go 零散知识点
交叉编译与国际化
交叉编译 :可在运行 Linux 系统的计算机上开发运行 Windows 下的应用程序。国际化 :Go 语言完全支持 UTF-8,源码文件格式也使用 UTF-8 编码。
Go 语言的标识符规则
导出标识符 :以大写字母开头的标识符可被外部包的代码使用。包内可见标识符 :以小写字母开头的标识符对包外不可见。
协程与通讯
协程调度 :协程间一般由应用程序显式实现调度,上下文切换无需下到内核层。协程通讯方式 :
共享内存型 :使用全局变量 + mutex 锁实现数据共享。消息传递型 :使用独有的 channel 机制进行异步通讯。
GC(垃圾回收)
GC 过程 :先 stop the world,扫描所有对象判活,标记可回收对象,恢复服务,同时起一个专门 goroutine 回收内存。GC 瓶颈 :每次都要扫描所有对象来判活,待收集的对象数目越多,速度越慢。
网络编程
Go 语言提供丰富便捷的网络编程接口,如:
socket 用 net.Dial
。http 用 http.Get/Post()
。rpc 用 client.Call('class_name.method_name', args, &reply)
。
Cgo 与语言交互
Cgo :Go 语言直接重用了大部份的 C 模块,称为 Cgo。与 C++ 交互替代方案 :
先将 C++ 编译成动态库,再由 Go 调用一段 C 代码。 使用 swig。
包引用规则
变量
变量定义了就要使用,否则无法通过编译。 在相同的代码块中,不可以再次对于相同名称的变量使用初始化声明。
defer 机制
Go 语言提供关键字 defer
,可指定延迟执行的逻辑体,在函数体 return 前或出现 panic 时执行。
测试源码文件
测试源码文件以 _test.go
结尾,使用 Go 的内置测试框架 testing
。
测试函数
功能测试函数 :名称以 Test
为名称前缀的函数,只能接受 *testing.T
的参数。性能测试函数 :名称以 Benchmark
为名称前缀的函数,只能接受 *testing.B
的参数。
编程规范
一、包相关规范
包名 :保持 package 的名字和目录一致,尽量采用简短且有意义的包名。包注释 :每个包都要有包注释,位于 package 子句之前。
二、文件命名规范
文件名应简短且有意义,由小写单词组成,使用下划线分隔各个单词。
三、结构体相关规范
命名 :采用驼峰命名法,首字母根据访问控制大写或者小写。申明和初始化格式 :采用多行。
四、接口相关规范
命名 :规则基本和结构体类型一致。单个函数的结构名以 “er” 作为后缀 ,例如 Reader
, Writer
。
五、变量命名规范
变量名称一般遵循驼峰法,首字母根据访问控制原则大写或者小写。 若变量类型为 bool 类型,则名称应以 Has
, Is
, Can
或 Allow
开头。
六、常量命名规范
常量均需使用全部大写字母组成,并使用下划线分词。 对于枚举类型的常量,需要先创建相应类型。
七、方法注释规范
方法注释应包含方法功能说明、参数说明和返回值说明。
八、import 规范
九、错误处理规范
不能丢弃任何有返回 err
的调用,必须全部处理。 尽早 return:一旦有错误发生,马上返回。 尽量不要使用 panic
,除非明确知道在做什么。 错误描述如果是英文必须为小写,不需要标点结尾。 采用独立的错误流进行处理。
十、其他编程规范
GO 语言的编程规范强制集成在语言中,明确规定花括号摆放位置。 强制要求一行一句。 不允许导入没有使用的包。 不允许定义没有使用的变量。 提供 gofmt
工具强制格式化代码。
常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。 常量可以作为枚举,常量组中如不指定类型和初始化值,则与上一行非空常量右值相同。
基础输入输出
fmt.Print :用于打印输出内容,不会自动换行。Println :用于打印输出内容,并在结尾添加换行符。Printf :用于格式化输出内容,可以使用占位符指定格式。Sprint :用于将内容格式化为字符串,并返回该字符串。Sprintln :用于将内容格式化为字符串,并在结尾添加换行符,返回该字符串。Sprintf :用于将内容格式化为字符串,可以使用占位符指定格式,返回该字符串。Scan :用于从标准输入中读取数据,并将数据存储到指定的变量中。Scanln :用于从标准输入中读取数据,并将数据存储到指定的变量中,读取到换行符时停止。Scanf :用于从标准输入中按照指定的格式读取数据,并将数据存储到指定的变量中。
示例
package main
import (
"fmt"
"os"
"bufio"
)
func main ( ) {
fmt. Println ( "请输入一个字符串:" )
reader := bufio. NewReader ( os. Stdin)
s1, _ := reader. ReadString ( '\n' )
fmt. Println ( "读到的数据:" , s1)
}