Go语言从入门到实战

一、Go语言背景和发展

1.软件开发的新挑战

  • 多核硬件架构
  • 超大规模分布式计算集群
  • Web模式导致的前所未有的开发规模和更新速度

2.Go的三位创始人

  • Rob Pike:Unix的早期开发者,UTF-8创始人
  • Ken Thompson:Unix的创始人,C语言创始人,1983年获图灵奖
  • Robert Griesemer:Google V8 JS Engine开发者,Hot Spot开发者

3.Go语言特点

  • 简单:Go只有25个关键字;特别是对于一些复杂编程任务如:并发编程,内存管理,Go语言有内置的并发支持及GC
  • 高效:Go是编译的静态类型语言,并且可以通过指针进行直接内存访问
  • 生产力:简单清新的依赖管理,简单清新的语法,以及独特的接口类型

二、第一个Go程序

[图片上传失败...(image-8dd3db-1556979504914)]

1.应用程序入口

  • 必须是main包
  • package main
  • 必须是main方法
  • func main()
  • 文件名不一定是main.go

2.退出返回值

  • Go中main函数不支持任何返回值
  • 通过os.Exit来返回状态

3.获取命令行参数

  • main函数不支持传入参数
  • 在程序中直接通过os.Args获取命令行参数

4.基本数据类型

  • bool
  • string
  • int int8 int16 int32 int64
  • uint uint8 uint16 uint32 uint64
  • byte // alias for uint8
  • rune
  • float32 float64
  • complex64 complex128

与其他主要编程的差异:

  1. Go语言不允许隐式类型转换
  2. 别名和原有类型也不能进行隐式类型转换

类型的预定义值:

  1. math.MaxInt64
  2. math.MaxFloat64
  3. math.MaxUint32

指针类型

  1. 不支持指针运算
  2. string是值类型,其默认的初始值为空字符串,而不是nil

5.运算符

用 == 比较数组

  • 相同维数且含有相同个数元素的数组才可以比较
  • 每个元素都相同的才相等

按位清零运算符

  • &^

6.循环

Go语言仅支持循环关键字for

for i := 0; i <= 9; I++

7.if条件

  1. condition表达式结果必须为布尔值
  2. 支持变量赋值:
if var declaration; condition {
    
}

8.switch条件

  1. 条件表达式不限制为常量或者整数
  2. 单个case中,可以出现多个结果选项,使用逗号分隔
  3. 与C语言等规则相反,Go语言不需要用break来明确退出一个case
  4. 可以不设定switch之后的条件表达式,在此种情况下,整个switch结构与多个if...else...的逻辑作用等同
switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
        //break
    case "linux":
        fmt.Println("Linux.")
    default:
        fmt.Println("%s.",os)
}
switch {
    case 0 <= Num && Num <= 3:
        fmt.Printf("0-3")
    case 4 <= Num && Num <= 6:
        fmt.Printf("4-6")
}
switch I {
    case 0,2:
        fmt.Printf("0-2")
    case 1,3:
        fmt.Printf("1-3")
}

9.Map元素的访问

在访问的Key不存在时,仍会返回零值,不能通过返回nil来判断元素是否存在

if v,ok := map1["key1"]; ok{
    
} else {
    
}

map的遍历

for k,v := range map1{
    
}

10.Map与工厂模式

  • Map的value可以是一个方法
  • 与Go的Dock type接口方式一起,可以方便的实现单一方法对象的工厂模式

11.实现Set

Go的内置集合中没有Set实现,可以map[type]bool

  1. 元素的唯一性
  2. 基本操作
    1. 添加元素
    2. 判断元素是否存在
    3. 删除元素
    4. 元素个数

12.字符串

  1. string是数据类型,不是引用或指针类型
  2. string是只读的byte slice,len函数可以它所包含的byte数
  3. string的byte数组可以存放任何数据

13.Unicode UTF8

  1. Unicode是一种字符集(code point)
  2. UTF8是unicode的存储实现(转换为字节序列的规则)

14.常用字符串函数

  1. strings包(https://golang.org/pkg/strings/
  2. strconv包(https://golang.org/pkg/strconv

15.函数是一等公民

  1. 可以有多个返回值
  2. 所有参数都是值传递:slice、map、channel会有传引用的错觉
  3. 函数可以作为变量的值
  4. 函数可以作为参数和返回值

16.Go接口

  1. 接口为非入侵性,实现不依赖接口定义
  2. 所以接口的定义可以包含在接口使用者包内

17.空接口与断言

  1. 空接口可以表示任何类型
  2. 通过断言来将空接口转换为制定类型
v, ok := p.(int) //ok=true时为转换成功

18.Go接口最佳实践

  1. 倾向于使用小的接口定义,很多接口只包含一个方法
type Reader interface {
    Read(p []byte) (n int, err error)
}
type Writer interface {
    Write(p []byte) (n int,err error)
}
  1. 较大的接口定义,可以由多个小接口定义组合而成
type ReadWriter interface {
    Reader
    Writer
}
  1. 只依赖于必要功能的最小接口
func StoreData(reader Reader) error {
    ......
}

19.编写好的错误处理

  1. 没有异常机制
  2. error类型实现了error接口
type error interface {
    Error() string
}
  1. 可以通过errors.New来快速创建错误实例
errors.New("")

20.panic

  • panic用于不可以恢复的错误
  • panic退出前会执行defer指定的内容

panic vs os.Exit

  • os.Exit 退出时不会调用defer指定的函数
  • os.Exit 退出时不输出当前调用栈信息

recover

defer func() {
   if err := recover(); err != nil {
       //恢复错误
   } 
}()

21.package

  1. 基本复用模块单元
    1. 以首字母大写来表明可被包外代码访问
  2. 代码的package可以和所在的目录不一致
  3. 同一目录里的Go代码的package要保持一致
  4. 通过go get来获取远程依赖
    1. go get -u强制从网络更新远程依赖
  5. 注意代码在Github上的组织形式,以适应go get
    1. 直接以代码路径开始,不要有src

22.init方法

  • 在main被执行前,所有依赖的package的init方法都会被执行
  • 不同包的init函数按照包导入的依赖关系决定执行顺序
  • 每个包可以有多个init函数
  • 包的每个源文件也可以有多个init函数,这点比较特殊

23.依赖管理

Go未解决的依赖问题

  1. 同一环境下,不同项目使用同一包的不同版本
  2. 无法管理对包的特定版本的依赖

vendor路径
<p>随着Go1.5 release 版本的发布,vendor目录被添加到除了GOPATH和GOROOT之外的依赖目录查找的解决方案。在Go 1.6之前,你需要手动的设置环境变量</p>

查找依赖包路径的解决方案如下:

  1. 当前包下的vendor目录
  2. 向上级目录查找,直到找到src下的vendor目录
  3. 在GOPATH下面查找依赖包
  4. 在GOROOT目录下查找

常用的依赖管理

三、并发机制

1.Thread vs. Groutine

  1. 创建时默认的stack的大小
    1. JDK5以后Java Thread stack默认为1M
    2. Groutine的Stack初始化大小为2K
  2. 和KSE (kernel Space Entity)的对应关系
    1. Java Thread是1:1
    2. Groutine是M:N

2.Lock

package sync
    Mutex
    RWLock

WaiteGroup

3.CSP并发机制

CSP vs. Actor

  • 和Actor的直接通讯不同,CSP模式则是通过Channel进行通讯的,更松耦合一些
  • Go中channel是有容量限制并且独立于处理Groutine,而如Erlang,Actor模式中的mailbox容量是无限的,接受进程也总是被动处理消息

4.select

多渠道的选择

select {
    case ret := <- retCh1:
        t.Logf("result %s", ret)
    case ret := <- retCh2:
        t.Logf("result %s", ret)
    default:
        t.Error("No one returned")
}

超时控制

select {
    case ret := <- retCh:
        t.Logf("result %s", ret)
    case <- time.After(time.Second * 1):
        t.Error("time out")
}

5.channel的关闭

  • 向关闭的channel发送数据,会导致panic
  • v,ok <- ch;ok为bool值,true表示正常接受,false表示通道关闭
  • 所有的channel接受者都会在channel关闭时,立刻从阻塞等待中返回且上述ok值为false。这个广播机制常被利用,进行向多个订阅者同时发送信号。如:退出信号

6.Context与任务取消

  • 根Context:通过context.Background()创建
  • 子Context:context.WithCancel(parentContext)创建
    • ctx,cancel := context.WithCancel(context.Background())
  • 当前Context被取消时,基于他的子context都会被取消
  • 接收取消通知 <- ctx.Done()

7.单例模式(懒汉式,线程安全)

var once sync.Once
var obj *SingletonObj
func GetSingletonObj() *SingletonObj {
    once.Do(func(){
        fmt.Println("Create Singleton obj.")
        obj = &SingletonObj{}
    })
    return obj
}

8、对象池

9、sync.Pool总结

  • 适合于通过复用,降低复杂对象的创建和GC代价
  • 协程安全,会有锁的开销
  • 生命周期受GC影响,不适合于做连接池等,需自己管理生命周期的资源的池化

10、单元测试框架

Benchmark

BDD in Go

项目网站
https://github.com/smartystreets/goconvey

安装
go get -u github.com/smartystreets/goconvey/convey

启动WEB UI
$GOPATH/bin/goconvey

四、其他

1、reflect.TypeOf vs. reflect.ValueOf

  • reflect.TypeOf 返回类型(reflect.Type)
  • reflect.ValueOf 返回值 (reflect.Value)
  • 可以从reflect.Value获得类型
  • 通过kind的来判断类型

2、利用反射编写灵活的代码

  • 按名字访问结构的成员
reflect.ValueOf(*e).FieldByName("Name")
  • 按名字访问结构的方法
reflect.ValueOf(e).MethodByName("UpdateAge").Call([]reflect.Value{reflect.ValueOf(1)})

3、架构设计模式:Pipe-Filter模式

  • 非常适合与数据处理及数据分析系统
  • Filter封装数据处理的功能
  • 松耦合:Filter只跟数据(格式)耦合
  • Pipe用于连接Filter传递数据或者在异步处理过程中缓冲数据流(进程内同步调用,pipe演变为数据在方法调用间传递)

4、架构设计模式:Micro Kernel

特点

  • 易于扩展
  • 错误隔离
  • 保持架构一致性

要点

  • 内核包含公共流程或通用逻辑
  • 将可变或可扩展部分规划为扩展点
  • 抽象扩展点行为,定义接口
  • 利用插件进行扩展

5、更快的JSON解析

EasyJSON采用代码生成而非反射

  • 安装
    go get -u github.com/mailru/easyjson/
  • 使用
    easyjson -all <结构定义>.go

6、Http路由规则

  • URL分为两种,末尾是/:表示一个子树,后面可以跟其他子路径;末尾不是/,表示一个叶子,固定的路径(以/结尾的URL可以匹配它的任何子路径,比如/images会匹配/images/cute-cat.jpg)
  • 它采用最长匹配原则,如果有多个匹配,一定采用匹配路径最长的那个进行处理
  • 如果没有找到任何匹配项,会返回404错误

7、更好的Router

htttps://github.com/julienschmidt/httprouter

8、性能分析工具

准备工作

通过文件方式输出Profile

9、性能调优

常见分析指标

  • Wall Time
  • CPU Time
  • Block Time
  • Memory Time
  • GC times/time spent
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 数据类型 基本数据类型 零值 当一个变量或者新值被创建时, 如果没有为其明确指定初始值,go语言会自动初始化其值为...
    codefine阅读 413评论 0 1
  • 官方网站:https://golang.org/标准库文档:https://golang.org/pkg/在线编码...
    技术学习阅读 2,323评论 2 39
  • context.Context类型 context.Context类型(以下简称Context类型)是在Go 1....
    尼桑麻阅读 6,122评论 0 4
  • 环境搭建 Golang在Mac OS上的环境配置 使用Visual Studio Code辅助Go源码编写 VS ...
    陨石坠灭阅读 5,772评论 0 5
  • 回望青春 伸手挽留 他却坚定又缓慢的走 望眼中年 前方有我的父亲 他站在终点对我挥着手 “不急,慢慢走“ 我抓紧母...
    抓狂的喵星人阅读 185评论 0 1