0.1、索引https://waterflow.link/articles/1664080524986
1、未知的枚举值我们现在定义一个类型是unit32的Status,他可以作为枚举类型,我们定义了3种状态
type Status uint32const ( StatusOpen Status = iota StatusClosed StatusUnknown)
其中我们使用了iota,相关的用法自行google 。最终对应的状态就是:
0-开启状态,1-关闭状态,2-未知状态
现在我们假设有一个请求参数过来,数据结构如下:
{"Id": 1234,"Timestamp": 1563362390,"Status": 1}
可以看到是一个json类型的字符串,其中就包含了Status状态,我们的请求是希望把状态修改为关闭状态 。
然后我们在服务端创建一个结构体,方便把这些字段解析出来:
type Request struct { IDint`json:"Id"` Timestamp int`json:"Timestamp"` StatusStatus `json:"Status"`}
好了,我们在main中执行下代码,看下解析是否正确:
package mainimport ( "encoding/json" "fmt")type Status uint32const ( StatusOpen Status = iota StatusClosed StatusUnknown)type Request struct { IDint`json:"Id"` Timestamp int`json:"Timestamp"` StatusStatus `json:"Status"`}func main() { js := `{"Id": 1234,"Timestamp": 1563362390,"Status": 1}` request := &Request{} err := json.Unmarshal([]byte(js), request) if err != nil {fmt.Println(err)return }}
执行后的结果如下:
go run main.go&{1234 1563362390 1}
可以看到解析是没问题的 。
然而,让我们再提出一个未设置状态值的请求(无论出于何种原因):
{"Id": 1234,"Timestamp": 1563362390}
在这种情况下,请求结构的状态字段将被初始化为其零值(对于 uint32 类型:0) 。因此,StatusOpen 而不是 StatusUnknown 。
最佳实践是将枚举的未知值设置为 0:
type Status uint32const ( StatusUnknown Status = iota StatusOpen StatusClosed)
在这里,如果状态不是 JSON 请求的一部分,它将被初始化为 StatusUnknown,正如我们所期望的那样 。
2、指针无处不在?按值传递变量将创建此变量的副本 。而通过指针传递它只会复制内存地址 。
因此,传递指针总是会更快,对么?
如果你相信这一点,请看看这个例子 。这是一个 0.3 KB 数据结构的基准测试,我们通过指针和值传递和接收 。0.3 KB 并不大,但这与我们每天看到的数据结构类型(对于我们大多数人来说)应该相差不远 。
当我在本地环境中执行这些基准测试时,按值传递比按指针传递快 4 倍以上 。这可能有点违反直觉,对吧?
这其实与 Go 中如何管理内存有关 。我们都知道变量可以分配在堆上或栈上,也知道:
- 栈包含给定 goroutine 的正在进行的变量 。一旦函数返回,变量就会从堆栈中弹出 。
- 堆包含共享变量(全局变量等) 。
type foo struct{}func getFooValue() foo { var result foo // Do something return result}
这里,一个结果变量由当前的 goroutine 创建 。这个变量被压入当前堆栈 。一旦函数返回,客户端将收到此变量的副本 。变量本身从堆栈中弹出 。它仍然存在于内存中,直到它被另一个变量擦除,但它不能再被访问 。我们现在修改下上面的例子,使用指针:
type foo struct{}func getFooPointer() *foo { var result foo // Do something return &result}
结果变量仍然由当前的 goroutine 创建,但客户端将收到一个指针(变量地址的副本) 。如果结果变量从堆栈中弹出,则此函数的客户端无法再访问它 。在这种情况下,Go 编译器会将结果变量转移到可以共享变量的地方:堆 。
但是,传递指针是另一种情况 。例如:
type foo struct{}func main(){ p := &foo{} f(p)}
因为我们在同一个 goroutine 中调用 f,所以 p 变量不需要被转移 。它只是被压入堆栈,子函数可以访问它 。比如在 io.Reader 的 Read 方法中接收切片而不是返回切片的直接结果,也不会转移到堆上 。
但是返回一个切片(它是一个指针)会将其转移到堆中 。
为什么堆栈那么快?主要原因有两个:
- 堆栈不需要垃圾收集器 。正如我们所说,一个变量在创建后被简单地压入,然后在函数返回时从堆栈中弹出 。无需进行复杂的过程来回收未使用的变量等 。
- 堆栈属于一个 goroutine,因此与将变量存储在堆上相比,存储变量不需要同步 。这也导致性能增益 。
推荐阅读
- 沈腾|又帅又好笑!沈腾瘦身成功亮相华表奖 大秀俄语
- 删除|回顾:妻子手机蓝牙忘关,车内自动播放的一条语音,毁了5年婚姻!
- ChatGPT进入iPhone时刻:“Chat感”更强、可使用多种语言
- 周冬雨|周冬雨戛纳造型惨遭网友嫌弃,网友言语粗鄙,但说的好有道理!
- |陈萌独自去做产假,手拿B超单沉默不语,发文24字评价朱小伟
- 秋瓷炫|浪姐4:初代唱跳,周深铁粉孙悦拉满团魂,秋瓷炫韩语rap实力圈粉
- |同是中国儿媳都生了娃,吉娜在家说4种语言,秋瓷炫教儿子说韩语
- |落跑甜心女主官宣被女友求婚,言语幸福声援女同,称非第一次被求婚引争议
- 香菇可以泡一夜吗
- 吴千语|恋上百亿富三代,成功挤身名媛圈,戛纳生图曝光吴千语的真实状态