真正在工做中用Go的時間不久,因此也做爲新手,總結了一些常見的問題和坑編程
// 1.空指針反向引用不合法 package main func main() { var p *int = nil *p = 0 } // in Windows: stops only with: <exit code="-1073741819" msg="process crashed"/> // runtime error: invalid memory address or nil pointer dereference // 2.文字或者常量引用也不合法 const i = 5 ptr := &i //error: cannot take the address of i ptr2 := &10 //error: cannot take the address of 10
// sort 包 import "sort" sort.Strings(keys)
type T int func main() { c := make(chan T) close(c) } // select 用法 var c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: fmt.Printf("received ", i1, " from c1\n") case c2 <- i2: fmt.Printf("sent ", i2, " to c2\n") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { fmt.Printf("received ", i3, " from c3\n") } else { fmt.Printf("c3 is closed\n") } default: fmt.Printf("no communication\n") }
len 用於返回某個類型的長度或數量(字符串、數組、切片、map 和管道);數組
cap 是容量的意思,用於返回某個類型的最大容量(只能用於切片和 map)併發
new 和 make 均是用於分配內存:new 用於值類型和用戶定義的類型,如自定義結構,make 用於內置引用類型(切片、map 和管道)。app
它們的用法就像是函數,可是將類型做爲參數:new (type)、make (type)。new (T) 分配類型 T 的零值並返回其地址,也就是指向類型 T 的指針。函數
它也能夠被用於基本類型:v := new(int)。make (T) 返回類型 T 的初始化以後的值,所以它比 new 進行更多的工做,new () 是一個函數,不要忘記它的括號性能
用於複製和鏈接切片大數據
二者均用於錯誤處理機制ui
底層打印函數,在部署環境中建議使用 fmt 包人工智能
操做複數,使用場景很少線程
Go 語言不支持這項特性的主要緣由是函數重載須要進行多餘的類型匹配影響性能;沒有重載意味着只是一個簡單的函數調度。因此你須要給不一樣的函數使用不一樣的名字,咱們一般會根據函數的特徵對函數進行命名
若是須要申明一個在外部定義的函數,你只須要給出函數名與函數簽名,不須要給出函數體:
func flushICache(begin, end uintptr) // implemented externally
函數也能夠以申明的方式被使用,做爲一個函數類型,就像:
type binOp func(int, int) int
最佳實踐:讀數據能夠用key,value,寫數據用地址,若是要把地址賦值給另外的map,那麼須要用臨時變量
kvMap := make(map[int]int) kvMap[0] = 100 kvMap[1] = 101 kvMap[2] = 102 kvMap[3] = 103 for k, v := range kvMap { println(k, &k, v, &v) } // 0 0xc000049e50 100 0xc000049e48 // 1 0xc000049e50 101 0xc000049e48 // 2 0xc000049e50 102 0xc000049e48 // 3 0xc000049e50 103 0xc000049e48
// Version A: items := make([]map[int]int, 5) for i:= range items { items[i] = make(map[int]int, 1) items[i][1] = 2 } fmt.Printf("Version A: Value of items: %v\n", items) // Version B: NOT GOOD! items2 := make([]map[int]int, 5) for _, item := range items2 { item = make(map[int]int, 1) // item is only a copy of the slice element. item[1] = 2 // This 'item' will be lost on the next iteration. } fmt.Printf("Version B: Value of items: %v\n", items2)
應當像 A 版本那樣經過索引使用切片的 map 元素。在 B 版本中得到的項只是 map 值的一個拷貝而已,因此真正的 map 元素沒有獲得初始化
併發編程在大部分語言裏面都會有,用來解決多個線程對臨界資源的訪問,經典的作法是一次只能讓一個線程對共享變量進行操做。當變量被一個線程改變時 (臨界區),咱們爲它上鎖,直到這個線程執行完成並解鎖後,其餘線程才能訪問它,Go語言的這種鎖機制是經過sync包中的Mutex來實現訪問的,下面是一個例子,另外在sync包中還有一個讀寫鎖,RWMutex ,其寫互斥的方法與Mutex同樣,讀互斥採用下面的方法
mu sync.Mutex func update(a int) { mu.Lock() a = xxx mu.Unlock() } mu2 sync.RWMutex mu2.RLock() mu2.RUnlock()
吳邪,小三爺,混跡於後臺,大數據,人工智能領域的小菜鳥。
更多請關注