分类 Go 中的文章

Golang源码阅读 Bufio阅读

基本实现 实现带缓存的I/O模块 对io.Reader和io.Writer进行封装 实现带缓存 对字符的I/O操作友好 Reader(缓存输入) 实现了一个带缓存的io.Reader 数据结构 1 2 3 4 5 6 7 8 type Reader struct { buf []byte // 缓存 rd io.Reader // 被包装的io.Reader对象 r, w int // buf切片上的索引,r代表读取的索引,w代表写入的索引 err error // 用来存储该Reader在执行中遇到的error lastByte int // 已读取的最后一个字节; -1 代表无效 lastRuneSize int // 已读取的最后一个rune; -1 代表无效 } 默认信息 1 2 const minReadBufferSize = 16 // buf最小长度为16字节 const maxConsecutiveEmptyReads = 100 // 一次读取,在连续100次没读取到会认为失败 关键代码逻辑 func (b *Reader) fill() 读取新的一个数据块,尽可能读满buf;只会读取成功读取一次,允许maxConsecutiveEmptyReads次读取失败,但是第一次读取成功后就不再读取,返回;……

阅读全文

当golang遇见工厂模式

工厂模式 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 介绍 意图 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。 主要解决 接口选择的问题。 何时使用 我们明确地计划不同条件下创建不同实例时。 如何解决 让其子类实现工厂接口,返回的也是一个抽象的产品。 关键代码 创建过程在其子类执行。 应用实例 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 Hibernate 换数据库只需换方言和驱动就可以。 优点 一个调用者想创建一个对象,只要知道其名称就可以了。 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 屏蔽产品的具体实现,调用者只关心产品的接口。 缺点 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。 使用场景 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。 注意事项 作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。 实现 现在有几个小孩:小明、小红、小白,现在要实现他们分别介绍自己的程序。我们将创建一个Child接口和实现Child接口的类。下一步是定义工厂类ChildFactory。 定义Child接口 1 2 3 type Child interface { IntroduceYourself() } 定义小明、小红、小白三个Child实现类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type Min struct { } func (Min) IntroduceYourself() { fmt.……

阅读全文

go-redis批量(pipeline)拉取数据的操作

主要没看见啥好的文档讲解,自己翻了翻源码,记录一下用法,见笑了 原理 在调用pipeline每次append命令时,会返回一个对应的xxxxCmd对象指针,保留这个指针即可,在Exec()函数执行完成后,会将结果写入对应的对象内 demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 package main import ( "context" "fmt" "github.……

阅读全文

Golang map数据结构接受json中的uint64数据

例如有一个json数据: 1 2 3 4 5 6 7 8 9 { "name": "小明", "money": 1111111111111111111 } 但是小明很有钱,他的钱用int64是存储不下来的,如果我们用一个结构体来接受数据就很简单,例如: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package main import ( "encoding/json" "fmt" ) type Info struct { Name string `json:"name"` Money uint64 `json:"money"` } func main() { info := &Info{} json.……

阅读全文

Golang源码阅读之map

源码地址:src/runtime/map.go 描述 Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。 Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。 ……

阅读全文

Golang重复对一个slice进行append造成数据错误

slice的属性 切片(slice)是建立在数组之上的更方便,更灵活,更强大的数据结构。切片并不存储任何元素而只是对现有数组的引用。 切片的长度是指切片中元素的个数。切片的容量是指从切片的起始元素开始到其底层数组中的最后一个元素的个数。 那么问题来了,几个不同的切片指向同一个数组,如果数组的值被改变会出现什么神奇的操作? 问题实例 slice的cap是怎么增长的 参考文章:How does Go slice capacity change on append? [duplicate] 有兴趣也可以看看golang的源码实现,在$GOPATH/src/runtime/slice.go slice的结构 1 2 3 4 5 6 7 8 9 10 11 type slice struct { array unsafe.Pointer len int cap int } 多次append造成的数据错误 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package main import "fmt" func main() { temp := []int{} temp = append(temp, 1) printSlice("temp", temp) temp = append(temp, 2) printSlice("temp", temp) temp = append(temp, 3) // temp := []int{1, 2, 3} printSlice("temp", temp) temp2 := append(temp, 4) printSlice("temp2", temp2) temp4 := append(temp, 5, 6) printSlice("temp4", temp4) temp3 := append(temp, 5) printSlice("temp3", temp3) printSlice("temp2", temp2) } func printSlice(valName string, s []int) { fmt.……

阅读全文

Golang交叉编译

Mac 下编译 Linux 和 Windows 64位可执行程序 1 2 3 4 5 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go Linux 下编译 Mac 和 Windows 64位可执行程序 1 2 3 4 5 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go Windows 下编译 Mac 和 Linux 64位可执行程序(cmd下) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 SET CGO_ENABLED=0 SET GOOS=darwin SET GOARCH=amd64 go build main.……

阅读全文

gorm软删除和唯一键冲突的问题

如果直接使用gorm.Model嵌入到自己的model中,就无法对DeletedAt进行附加的操作,最简单的方式就是将gorm.Model的内容拷贝出来,将DeletedAt加入到自己的unique_index中 ……

阅读全文

golang http.client 的 Connection reset by peer 问题

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func main() { req, err := http.NewRequest("GET", "http://www.baidu.com",nil ) if err != nil { log.Errorf("") } req.Close = true resp, err := http.Client.Do(req) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func main() { req, err := http.NewRequest("GET", "http://www.baidu.com",nil ) if err !……

阅读全文