文章目录
关键知识点总结
数据结构
一点奇淫,
看到语言中的新的数据结构时,一定要搞清楚这种新的数据结构在内部的实现的机制是什么以及数据的存储的数据结构,
例如切片的数据结构是怎样的。
1. map
2. 切片:动态数组。
并发协程
1. go协程
2. channel
3.
接口类型
interface是Go中用来实现OOP多态的手段,而Go中用来实现类的技术手段是struct。但Go有一个特别有意思的现象:
1. interface中只能定义函数,不能定义变量;
2. struct中声明的时候只能定义变量,而不能定义函数;
Go中的接口类型不是任意类型。
接口类型中包括变量的类型信息。
任意类型都能转换为接口类型。
go的value receiver和pointer recriver机制
type A interface {
CallName()
CallId()
}
type B struct {
Name string
Id int
}
func (b *B)CallName() {
fmt.Println(b.Name)
}
func (b B)CallId() {
fmt.Println(b.Name)
}
func TestValue() { // 失败,CallName的receiver是pointer,传入的只能为Pointer
var a A = B(Name : "")
a.CallName()
}
func TestPointer() {
var a A = &B(Name : "") // 成功,CallId的receiver是value,传入的可以为Pointer/Value
a.CallId()
}
反射机制
参考:https://draveness.me/golang/basic/golang-reflect.html
基本可以分为三种情况:
1. 从接口类型变量反射出反射类型对象;–> C/C++中typeof可实现本功能。
2. 从反射类型对象反射出接口类型变量;
3. 修改反射类型对象,其值必须可被设置;要对变量的指针进行反射操作。
关键方法
接口名称 | 接口定义 |
---|---|
reflect.Typeof | func TypeOf(i interface{}) Type |
reflect.ValueOf | func ValueOf(i interface{}) Value |
reflect.ValueOf | func (v Value) CanSet() bool |
reflect.ValueOf | func (v Value) Elem() Value |
实现原理
示例
// var to type
var circle float64 = 6.28
var icir interface{}
icir = circle
fmt.Println("Reflect:circle.Value=", reflect.ValueOf(icir))
fmt.Println("Reflect:circle.Type=", reflect.TypeOf(icir))
fmt.Println("Reflect:circle.Value=", reflect.ValueOf(circle))
fmt.Println("Reflect:circle.Type=", reflect.TypeOf(circle))
// interface to var
valueref := reflect.ValueOf(icir)
fmt.Println("valueref:", valueref)
fmt.Println("inteface:", valueref.Interface())
y := valueref.Interface().(float64)
fmt.Println("y:", y)
// change the interface
value := reflect.ValueOf(circle)
fmt.Println("value:", value)
fmt.Println("setability of value:", value.CanSet())
value2 := reflect.ValueOf(&circle)
fmt.Println("value2:", value2)
fmt.Println("setability of value2:", value2.CanSet())
value3 := value2.Elem()
fmt.Println("setability of value3:", value3.CanSet())
value3.SetFloat(3.14)
fmt.Println("value3:", value3)
fmt.Println("circle:", circle)
静态编译
https://johng.cn/cgo-enabled-affect-go-static-compile/
debug
关键特性
defer
- 多个defer被定义时,采取后定义先执行的规则
常用功能库总结
文件操作
1. path/filepath
2. io/ioutil
数据库操作
1. database/sql
命令行工具库
- urfave/cli
踩坑记录
真理:Go函数传递的均为值传递 --> 所有的函数调用都会导致值的拷贝,同样当实参类型与形参类型不一致时,会导致类型的隐形转换。
- 切片作为参数传入;接真理,但有时通过参数传入的值,函数内部的修改也会体现到函数外部,似乎是匪夷所思,又该怎样解释呢?其实指针也仅仅是个值,如果这个值(或被结构体封装后传入)传入函数内部,函数内部把这个值当成指针使用,你说内部的修改能不能体现到函数外部呢?
- 结构体中,成员变量以及成员函数,如果名字首字母大写,表示公有型变量,外部可以直接使用;如果名字首字母小写,表示私有型变量,外部不能直接使用;
GoLand编辑器
https://zhuyasen.com/post/glangIDE.html
https://learnku.com/articles/24924
编程规范
命名
- 变量命名:包内使用,首字母小写;保外使用,首字母大写;
代码结构
- 一个目录是一个package
- import包的顺序:标准库,系统库,第三方库,本项目的库,不同分组之间使用空行隔开
语言特性
- interface底层有两个成员变量,一个是类型;一个是值。只有二者均为nil时,interface才为nil;
- init函数是在所有变量声明均为初始化之后,才会被调用;一个文件内有一个init,包内的init函数执行顺序不确定。
- defer是在return执行之后,才会执行的函数;defer会导致性能下降;
- chan以及goroutine是go语言并发的设计核心;定义通道时,明确通道的读写类型;
编程实践
- 分配切片时,预估大小,按照容量进行空间分配;
- Go中的GC规则是扫描到变量中的最后一个指针时,即返回;因此应该把结构体中的指针和引用变量写到结构提靠前的位置;
常见错误
- multiple-value in single-value context
- use of package *** without selector
- range只能对切片等数据从开头作用,而不能从其中某一个元素开始作用;
- range(strs)
- range(strs[1])
- 使用go携程时,add操作和wait操作必须是串行执行