文章目錄
關鍵知識點總結
數據結構
一點奇淫,
看到語言中的新的數據結構時,一定要搞清楚這種新的數據結構在內部的實現的機制是什麼以及數據的存儲的數據結構,
例如切片的數據結構是怎樣的。
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操作必須是串行執行