Go语言开发技巧必知的小细节提升效率
引言
近年来,Go语言迅速占领了开发领域的重要地位,成为众多公司和开发者的首选语言。
其简捷、高效、并发性强的特点使得它在处理大型系统和复杂工程问题时表现出色,为开发者提供了良好的体验。
随着云计算、容器化、微服务、服务网格等技术的兴起,Go语言的应用场景愈发广泛,这也进一步推动其社区的繁荣和发展。
可以预见,Go语言的发展前景将会更加广阔。
本文分享几个你可能不知道的Go语言小细节,希望能帮助大家更好地学习这门语言~~
01 数字字面量
Go语言中声明数字变量时,可以使用数字字面量让开发者以二进制、八进制或十六进制浮点数的格式定义数字。例如:
v1 := 0b00101101 // 二进制字面量
v2 := 0o377 // 八进制字面量
v3 := 0x1p-2 // 十六进制浮点字面量
v4 := 01e2 // 十进制浮点字面量
在表达数字字面量时,可以使用_分隔数字。例如:
v5 := 123_456 // 可以使用_分隔数字
02 切片表达式
切片表达式指从字符串、数组、指向数组或切片的指针构造子字符串或切片。
它有两种变体,其中一种是指定low和high两个索引界限值。
由于切片的底层是数组,所以我们可以基于数组通过切片表达式得到切片,切片表达式中的low和high表示索引范围(左包含,右不包含)。
例如,下面的代码表示从数组a中选出1≤索引值<4的元素组成切片s,切片s的长度为high-low,容量为其底层数组的容量。
// 对数组取切片 a := [5]int{1, 2, 3, 4, 5} s := a[1:3] // s := a[low:high] fmt.Printf("s:%v type:%T len:%v cap:%v\n", s, s, len(s), cap(s)) // 对字符串取切片得到的还是字符串类型 b := "hello world" s2 := b[1:3] // s2 := b[low:high] fmt.Printf("s2:%v type:%T len:%v\n", s2, s2, len(s2))
输出:
s:[2 3] type:[]int len:2 cap:4
s2:el type:string len:2
方便起见,可以省略切片表达式中的任何索引。如果省略low则默认为0,如果省略high则默认为切片操作数的长度。
a[2:] // 等同于 a[2:len(a)]
a[:3] // 等同于 a[0:3]
a[:] // 等同于 a[0:len(a)]
注意:对于数组或字符串,如果0 ≤ low ≤ high ≤ len(a),则索引合法;否则会索引越界(out of range)。
对切片再执行切片表达式时(切片再切片),high的上限是切片的容量cap(a),而不是长度。
常量索引必须是非负的,并且可以用int类型的值表示。
对于数组或常量字符串,常量索引必须在有效范围内。
如果low和high两个指标都是常数,则它们必须满足low≤high。
如果索引在运行时超出范围,就会发生运行时panic。
a := [5]int{1, 2, 3, 4, 5} s := a[1:3] // s := a[low:high] fmt.Printf("s:%v len:%v cap:%v\n", s, len(s), cap(s)) s2 := s[3:4] // 索引的上限是cap(s)而不是len(s) fmt.Printf("s2:%v len:%v cap:%v\n", s2, len(s2), cap(s2))
输出:
s:[2 3] len:2 cap:4
s2:[5] len:1 cap:1
另一种变体是除了指定low和high索引界限值,还指定容量的完整形式。
注意:字符串不支持完整切片表达式。
a[low:high:max]
上面的代码会构造与简单切片表达式a[low:high]的类型、长度和元素相同的切片。
另外,它会将得到的结果切片的容量设置为max-low。
在完整切片表达式中只有第一个索引值(low)可以省略,该值默认为0。
a := [5]int{1, 2, 3, 4, 5} s1 := a[1:3:4] // 通过额外指定max,控制切片的容量 fmt.Printf("s1:%v len:%v cap:%v\n", s1, len(s1), cap(s1)) s2 := a[1:3] fmt.Printf("s2:%v len:%v cap:%v\n", s2, len(s2), cap(s2))
输出结果:
s1:[2 3] len:2 cap:3
s2:[2 3] len:2 cap:4
完整切片表达式需要满足的条件是0 ≤ low ≤ high ≤ max ≤ cap(a),其他条件和简单切片表达式相同。
03 go test cache
在包列表模式下,go test会缓存测试成功的包的测试结果,以避免运行不必要的重复测试。
当测试结果可以从缓存中获取时,go test将直接显示以前缓存的输出,而不是再次运行测试二进制文件。
当这种情况发生时,go test会输出(cached)来代替摘要行中的运行时间。
执行两次 go test . -v,从下面的输出结果可以看到,第二次的输出结果中有cached标识。
❯ go test . -v === RUN TestSplit --- PASS: TestSplit (0.00s) PASS ok split 0.005s ❯ go test . -v === RUN TestSplit --- PASS: TestSplit (0.00s) PASS ok split (cached)
如果多次执行测试时运行的二进制文件相同,并且命令行上的参数都是可缓存测试参数(-bachtime、-cpu、-list、-pallel、-run、-short、-timeout、-failfast和-v),就会匹配到缓存中的结果。
只要测试时添加了除上述可缓存参数外的任何参数就不会缓存结果,显式禁用测试缓存的惯用方法是在命令行使用 -count=1 参数。
❯ go test . -v -count=1 === RUN TestSplit --- PASS: TestSplit (0.00s) PASS ok split 0.005s
04 JSON序列化时不转义
json包中的encoder可以通过SetEscapeHTML指定是否应该在JSON字符串中转义有问题的HTML字符。
它默认将&、<和>转义为\u0026、\u003c和\u003e,以避免在HTML中嵌入JSON时出现安全问题。
如果在是非HTML场景下不想被转义,那么可以通过SetEscapeHTML(false)禁用此行为。
例如,在有些业务场景下可能需要序列化带查询参数的URL,我们并不希望转义&符号。
// URLInfo 一个包含URL字段的结构体 type URLInfo struct { URL string // ... } func jsonEncodeDontEscapeHTML(data URLInfo) { // 默认序列化时会转义 &、<和> b, _ := json.Marshal(data) fmt.Printf("json.Marshal(data) result:%s\n", b) // 通过 SetEscapeHTML(false) 设置不转义 buf := bytes.Buffer{} encoder := json.NewEncoder(&buf) encoder.SetEscapeHTML(false) encoder.Encode(data) fmt.Printf("encoder.Encode(data) result:%s\n", buf.String()) } func main() { jsonEncodeDontEscapeHTML(URLInfo{URL:"https://liwenzhou.com?name=q1mi&age=18"}) }
输出结果如下:
json.Marshal(data)
result:{"URL":"https://liwenzhou.com?name=q1mi\u0026age=18"}
encoder.Encode(data)
result:{"URL":"https://liwenzhou.com?name=q1mi&age=18"}
以上就是Go语言开发技巧必知的小细节提升效率的详细内容,更多关于Go语言开发技巧的资料请关注脚本之家其它相关文章!
相关文章
Go语言Web编程实现Get和Post请求发送与解析的方法详解
这篇文章主要介绍了Go语言Web编程实现Get和Post请求发送与解析的方法,结合实例形式分析了Go语言客户端、服务器端结合实现web数据get、post发送与接收数据的相关操作技巧,需要的朋友可以参考下2017-06-06
最新评论