gocookbook icon indicating copy to clipboard operation
gocookbook copied to clipboard

go cook book

Results 90 gocookbook issues
Sort by recently updated
recently updated
newest added

在Go中字符串是原生类型,是只读的,所以用"+"操作符进行字符串时会创建一个新的字符串。如果在循环中使用"+"进行字符串拼接则会创建多个字符串,比如下面这样: ```go var s string for i := 0; i < 1000; i++ { s += "a" } ``` 那么怎么更高效得进行字符串拼接呢?在早先`Go1.10` 以前使用的是`bytes.Buffer`。 ```go package main import ( "bytes" "fmt" ) func...

错误处理这块是Go日常被大家吐槽较多的地方,我在工作中也观察到一些现象,比较严重的是在各层级的逻辑代码中对错误的处理有些重复。 比如,有人写代码就会在每一层都判断错误并记录日志,从代码层面看,貌似很严谨,但是如果看日志会发现一堆重复的信息,等到排查问题时反而会造成干扰。 这里总结三点`Go`代码的错误处理相关的最佳实践。 >这些最佳实践也是网上一些前辈分享的,我自己实践后在这里用自己的语言描述出来,希望能对大家有所帮助 ## 认识error `Go`程序通过`error`类型的值表示错误 `error`类型是一个内建接口类型,该接口只规定了一个返回字符串值的`Error方法`。 ```go type error interface { Error() string } ``` `Go`语言的函数经常会返回一个`error`值,调用者通过测试`error`值是否是`nil`来进行错误处理。 ```go i, err := strconv.Atoi("42") if err != nil { fmt.Printf("couldn't convert...

> **注:所有内容摘录自 [Go 语言接口的实现原理](https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-interface),这里是读书笔记。** **动态派发(Dynamic dispatch)是在运行期间选择具体多态操作(方法或者函数)执行的过程**,它是面向对象语言中的常见特性。`Go` 语言虽然不是严格意义上的面向对象语言,但是接口的引入为它带来了动态派发这一特性,**调用接口类型的方法时,如果编译期间不能确认接口的类型,`Go`语言会在运行期间决定具体调用该方法的哪个实现**。 在如下所示的代码中,`main` 函数调用了两次 `Quack` 方法: 1. 第一次以 `Duck` 接口类型的身份调用,调用时需要经过运行时的动态派发; 2. 第二次以 `*Cat` 具体类型的身份调用,编译期就会确定调用的函数: ```go package main type Duck interface { Quack() } type Cat...

> **注:所有内容摘录自 [Go 语言接口的实现原理](https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-interface),为该文章的读书笔记。** ### 接口类型 接口也是 Go 语言中的一种类型,它能够出现在变量的定义、函数的入参和返回值的类型定义部分它们进行类型约束,不过 Go 语言中有两种略微不同的接口,一种是带有一组方法的接口,另一种是不带任何方法的空接口 interface{}。 Go 语言使用 [runtime.iface](https://github.com/golang/go/blob/6c64b6db6802818dd9a4789cdd564f19b70b6b4c/src/runtime/runtime2.go#L203) 表示包含方法签名的接口,使用 [runtime.eface](https://github.com/golang/go/blob/6c64b6db6802818dd9a4789cdd564f19b70b6b4c/src/runtime/runtime2.go#L208) 表示不包含任何方法的空接口 interface{}。 ```go type iface struct { tab *itab data unsafe.Pointer } ```...

### 读取请求 接收请求涉及的内容较多,在我公众号的文章中已经有详细概况总结过,具体查看文章:「[深入学习解析HTTP请求](https://mp.weixin.qq.com/s/ie5HwvDaP9QXYFCjjNXYtw)」 ### 发起请求 ```go func httpRequest(method string, url string, options ...*Option) (code int, content string, err error) { start := time.Now() reqOpts := defaultRequestOptions() // 默认的请求选项 for _,...

啥是原子操作呢?顾名思义,原子操作就是具备原子性的操作... 是不是感觉说了跟没说一样,原子性的解释如下: >一个或者多个操作在 CPU 执行的过程中不被中断的特性,称为*原子性(atomicity)* 。这些操作对外表现成一个不可分割的整体,他们要么都执行,要么都不执行,外界不会看到他们只执行到一半的状态。 ### Go 语言提供了哪些原子操作 `Go`语言通过内置包`sync/atomic`提供了对原子操作的支持,其提供的原子操作有以下几大类: - 增减,操作方法的命名方式为`AddXXXType` - 载入,保证了读取到操作数前没有其他任务对它进行变更,操作方法的命名方式为`LoadXXXType` - 存储,有载入了就必然有存储操作,这类操作的方法名以`Store`开头 - 比较并交换,操作方法以`CompareAndSwap`开通,也就是`CAS`,像`Go`的很多并发原语实现就是依赖的`CAS`操作 - 交换,一组以`Store`开头的操作方法,这个简单粗暴一些,不比较直接交换,一般不怎么用这个操作 ### 互斥锁跟原子操作的区别 - 使用目的区别:互斥锁是用来保护一段逻辑,原子操作用于对一个变量的更新保护。 - 底层实现区别:`Mutex`由**操作系统**的调度器实现,而`atomic`包中的原子操作则由**底层硬件指令**直接提供支持,这些指令在执行的过程中是不允许中断的,因此原子操作可以在`lock-free`的情况下保证并发安全,并且它的性能也能做到随`CPU`个数的增多而线性扩展。 #### 原子操作增加、载入 ```go func...

Context 与 Go 语言中的并发编程有着比较密切的关系,在其他语言中我们很难见到类似 Context 的东西,它不仅能够用来设置截止日期、同步『信号』还能用来传递请求相关的值。 Go 语言里每一个并发的执行单元叫做 goroutine,当一个用Go语言编写的程序启动时,main 函数在一个单独的 goroutine 中运行。main 函数返回时,所有的goroutine都会被直接打断,程序退出。除此之外如果想通过编程的方法让一个goroutine 中断其他 goroutine 的执行,只能是通过在多个 goroutine 间用 context 上下文对象同步取消信号的方式来实现。 Context 其实是 Go 语言 context 包对外暴露的接口, ```go type Context interface...

### 巧用WaitGroup 因为go对并发的原生支持使得并发编程难度大大降低,刚学会Go语言的人特别喜欢在开发的时候尝试并发,其实并发并不是解决所有问题的银弹,反而是一味想尝试并发造成了不少线上BUG/事故。比如说,有的人会误以为起几十个线程休眠一下,再接着起线程就能控制并发数了,其实不是,比如像下面这么写 ```go func badConcurrency() { batchSize := 50 for { data, _ := queryDataWithSizeN(batchSize) if len(data) == 0 { break } for _, item := range data {...

在计算机和信息技术领域里`I/O`这个术语表示输入 / 输出 ( 英语:Input / Output ) ,通常指数据在存储器(内部和外部)或其他周边设备之间的输入和输出,是信息处理系统与外部之间的通信。输入是系统接收的信号或数据,输出则是从其发送的信号或数据。 在Go语言中涉及`I/O`操作的内置库有很多种,比如:`io`库,`os`库,`ioutil`库,`bufio`库,`bytes`库,`strings`库等等。 拥有这么多内置库是好事,但是具体到涉及`I/O`的场景我们应该选择哪个库呢? ### io.Reader/Writer Go语言里使用`io.Reader`和`io.Writer`两个 interface 来抽象`I/O`,他们的定义如下。 ```go type Reader interface { Read(p []byte) (n int, err error) } type Writer...

#### 题目是这样的: > 有一个名叫大自然的搬运工的工厂,生产一种叫做一氧化二氢的神秘液体。这种液体的分子是由一个氧原子和两个氢原子组成的,也就是水。 > > 这个工厂有多条生产线,每条生产线负责生产氧原子或者是氢原子,每条生产线由一个 goroutine 负责。 > > 这些生产线会通过一个栅栏,只有一个氧原子生产线和两个氢原子生产线都准备好,才能生成出一个水分子,否则所有的生产线都会处于等待状态。也就是说,一个水分子必须由三个不同的生产线提供原子,而且水分子是一个一个按照顺序产生的,每生产一个水分子,就会打印出 HHO、HOH、OHH 三种形式的其中一种。HHH、OOH、OHO、HOO、OOO 都是不允许的。 > > 生产线中氢原子的生产线为 2N 条,氧原子的生产线为 N 条。 #### 实现思路 首先,我们来定义一个 H2O 辅助数据类型,它包含两个信号量的字段和一个循环栅栏。 1. semaH 信号量:控制氢原子。一个水分子需要两个氢原子,所以,氢原子的空槽数设置为...