Type
-
定义结构体
-
定义接口
-
定义类型别名:
起别名实际上是为了更好的理解代码
语法:
type MyInt = int,在编译时类型别名会被直接替换为inttype MyInt = int var i MyInt = 8 var j int = 12 fmt.Println(i + j) fmt.Printf("%T\n", i) // 输出:int -
类型定义
自定义类型,是基于已有的类型。既可以使用原已有类型的特性,又可扩展自己自定义的功能。
语法:
type MyInt inttype MyInt int func (mi MyInt) string() string { // 扩展的自定义方法 return strconv.Itoa(int(mi)) } var i MyInt = 8 var j int = 12 // fmt.Println(i + j) 错误!!!不可以这样用! fmt.Println(int(i) + j) // 正确操作方法 fmt.Printf("%T\n", i) // 输出:main.MyInt fmt.Println(i.string()) // 基于int类型,定义MyInt类型,并扩展自定义方法 fmt.Printf("%T\n", i.string()) // 输出:string -
类型判断
var a interface{} = "abc" switch a.(type) { // 类型判断 case string: fmt.Println("string:", a) // strting:abc } m, _ := a.(string) // 类型断言 fmt.Println(m)
字符串
在Go语言中,字符串是不可变的,意味着不能通过下标直接修改字符串的内容。下面这段翻转字符串的程序就是错误的:
func reverse(s string, start, len int) string {
for i := 0; i < len / 2; i++ {
s[start+i], s[start+len-1-i] = s[start+len-1-i], s[start+i]
}
return s
}
报错:cannot assign to s[start + i] (neither addressable nor a map index expression) , 即:无法将值赋给
s[start + i](既不是地址可访问的,也不是可作为映射索引表达式的)
若想修改字符串中的内容,可以先把字符串转为rune切片或者byte切片,修改后再转为string类型,下面是更改后的代码:
func reverse(s string, start, len int) string {
byteSlice := []byte(s)
for i := 0; i < len / 2; i++ {
byteSlice[start+i], byteSlice[start+len-1-i] = byteSlice[start+len-1-i], byteSlice[start+i]
}
return string(byteSlice)
}
Go并发编程
- Go语言进程间通信
- 基于共享内存的通信,可能会产生数据竞态,影响性能
- 在项目开发过程中,并发安全的错误问题较难定位,所以应该尽量避免对共享内存做非并发安全的读写操作
Go依赖管理
GoPATH和GoVendor都是通过引入源码的副本进行依赖,并没有版本规则的概念,只有到了GoModule阶段才真正引入版本的概念。
测试
- 单元测试
- 单元测试-规则
m.Run()会运行本package下的所有TestXxx函数 - 单元测试-覆盖率
go test xxx_test.go --cover命令会测试覆盖率,覆盖率也即进行测试时,被进行测试的函数执行到的行数除以总的行数- 一般覆盖率:50%~60%,较高覆盖率80%+
- 单元测试-规则
- 基准测试:测试一段程序运行时的性能和CPU的损耗
- 基准测试-规则
- 测试函数签名
func BenchmarkXxx(b *testing.B)
- 测试函数签名
- 基准测试-规则