Go语言实战读书笔记
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
Go語言實戰(zhàn)讀書筆記
第二章
通道(channel)、映射(map)和切片(slice)是引用類型。引用類型的對象需要使用make函數(shù)進行構(gòu)造。
在Go程序中,如果函數(shù)main()返回,整個程序就終止了。這時,Go會關(guān)閉全部goroutine。
使用for range迭代切片時,每次迭代前會返回兩個值:元素在切片中的索引和元素副本。
Go支持閉包。
解析JSON示例:
type Feed struct {Name string `json:"site"`URI string `json:"link"`Type string `json:"type"` }file, _ := os.Open(filename) var feeds []*Feed json.NewDecoder(file).Decode(&feeds)聲明接口示例:
type Matcher interface {Search(feed *Feed, searchTerm string) ([]*Result, error) }使用指針作為接受者聲明的方法,只能由指針調(diào)用。使用值作為接受者聲明的方法,值和指針都可以調(diào)用。當(dāng)使用值調(diào)用時,傳入方法的是值的副本。
如果使用for range對通道進行迭代時,當(dāng)通道關(guān)閉后,迭代會終止。
除了main包外,Go包應(yīng)當(dāng)與其所在目錄同名。
第三章
Go在尋找包時,先從$GOROOT目錄下尋找,接著在$GOPATH目錄下尋找。
命名導(dǎo)入:
import myfmt "mylib/fmt" import _ "mylib/init"包的初始化。每個包可以包含多個init函數(shù),這些函數(shù)將在main.main()之前執(zhí)行。
Go工具
構(gòu)建:
go build hello.go # 構(gòu)建指定文件。 go build # 構(gòu)建當(dāng)前目錄。 go build github.com/goinaction/code/chapter3/wordcount # 構(gòu)建指定包。 go build github.com/goinaction/code/chapter3/... # 構(gòu)建指定目錄下的全部包。清理構(gòu)建文件:
go clean hello.go構(gòu)建并執(zhí)行:
go run hello.go檢查代碼中的常見錯誤:
go vet go vet main.go go vet .格式化代碼:
go fmt gofmt -l -w -s .查看文檔:
go doc tar godoc -http=:6060Go源代碼文檔
函數(shù)文檔示例:
// Retrieve 連接到配置庫,收集各種鏈接設(shè)置、用戶名和密碼。這個函數(shù)成功時 // 返回 config 結(jié)構(gòu),否則返回一個錯誤。 func Retrieve() (config, error) {// ... }包文檔示例:
// 包 usb 提供了用于調(diào)用 USB 設(shè)備的類型和函數(shù)。 package usb // ...第四章
聲明數(shù)組:
var a1 [5]int var a2 = [3]int{1, 2, 3} var a3 = [...]int{1, 2, 3} var a4 = [3]*int{0: new(int), 1: new(int)}數(shù)組賦值會復(fù)制元素:
a1 := [3]string{"a", "b", "c"} var a2 [3]string a2 = a1多維數(shù)組:
var a1 [4][2]int a2 := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} a3 := [4][2]int{1: {0: 20}, 3: {1: 41}} var a4 [2]int = a3[1]不要用數(shù)組作為函數(shù)參數(shù)。這么做會復(fù)制大量對象。要使用切片。
建立切片:
s1 := make([]int, 5) s2 := make([]int, 3, 5) s3 := []{1, 2, 3} s4 := []string{99: ""} s5 := s1[1:3] # s5和s1共享同一個底層數(shù)組 s6 := s1[2:3:4] # s6是長度為1,容量為2的切片切片會包含一個底層數(shù)組。
切片和數(shù)組的區(qū)別在于,[]中沒有數(shù)字。
對于底層數(shù)組容量是k的切片s[i:j],其長度是j-i,容量是k-i。
在對切片進行迭代時,返回的是切片元素的副本。每次迭代時,值副本的地址是相同的。
多維切片:
s := [][]int{{10}, {100, 200}}切片包含地址指針、長度和容量。在64位計算機上,一個切片占用24字節(jié)。復(fù)制切片時不會復(fù)制底層數(shù)組,因此將切片作為參數(shù)傳遞給函數(shù),開銷很小。
切片函數(shù):
cap(s) # 容量 len(s) # 長度 append(s, element)映射使用了散列表。在每次迭代中,各元素返回的次序可能不同。
建立映射:
m1 := make(map[int]int) m2 := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}映射的鍵必須是可以使用==比較的對象。函數(shù)、切片、以及包含切片的對象,由于具有引用語義,不能作為映射的鍵。
從映射中獲取鍵對應(yīng)的值時,如果鍵不存在,會返回零值。
映射函數(shù):
delete(m, "key")第五章
Go是靜態(tài)類型語言。
自定義類型字面值:
type user struct {name stringemail string }type admin struct {person userlevel string }u1 := user{"Lisa", "lisa@abc.com"} u2 := user{name: "Lisa", email: "lisa@abc.com"} a1 := admin{person: user{"Lisa", "lisa@abc.com"}level: "super" }以指針為接收者的函數(shù)只能通過指針調(diào)用。以值為接收者的函數(shù)可以通過值或指針調(diào)用。對于以值為接收者的函數(shù),函數(shù)域中的接收者是值的副本,即使通過指針調(diào)用時也是如此。
package mainimport ("log" )func main() {u1 := user{"Tom"}u2 := &user{"Jerry"}u1.Name()u2.Name()log.Printf("%p %p", &u1, u2) }type user struct {name string }func (r user) Name() {log.Printf("%s %p %p", r.name, &r, &r.name) }如果函數(shù)需要修改接收者的狀態(tài),要以指針作為接收者。否則使用值作為接收者。
Go中的引用類型有:切片、映射、通道、接口和函數(shù)。
接口是用于定義行為的類型。如果一個類型實現(xiàn)了某個接口所聲明的全部方法,這個類型的對象就可以賦值給做對應(yīng)接口類型的變量。在賦值完成后, 會建立一個接口對象。接口對象包含兩個指針:一個指向iTable,一個指向存儲的值。iTable包含了存儲值的類型信息,以及與這個值相關(guān)聯(lián)的一組方法,稱為方法集。方法集定義了接口的接收規(guī)則。
| 值 | 方法接收者 |
| T | (t T) |
| *T | (t T) 和 (t?*T) |
嵌入類型:
type user struct {name stringemail string }func (r user) hello() string {return "hello " + r.name }type admin struct {userlevel string }a := admin{} a.user.name a.name a.user.hello() a.hello()被嵌入的類型也叫內(nèi)部類型。內(nèi)部類型中的標(biāo)志符(成員和函數(shù))會被提升到外部類型中。
以小寫字母開頭的標(biāo)識符是包私有標(biāo)識符,在包外不可見。對于未公開的內(nèi)部類型,其公開成員可以通過標(biāo)識符提升,以外部類型成員的方式訪問。
第六章
Go使用的同步模型是通信順序模型(Communicating Sequential Processes,CSP),各個goroutine通過傳遞消息通信,而非通過鎖和共享內(nèi)存來共享狀態(tài)。
Go運行時會在邏輯處理器上調(diào)度goroutine。從1.5版本起,Go運行時會為每個物理處理器分配一個邏輯處理器(每個CPU一個還是每個核一個?)。當(dāng)goroutine指定到一個阻塞的系統(tǒng)調(diào)用時,運行時將線程和goroutine從邏輯處理器上分離。被分離的線程會繼續(xù)阻塞,等待系統(tǒng)調(diào)用返回。而邏輯處理器會建立一個新線程,從隊列中選取一個goroutine,將新線程和goroutine綁定到邏輯處理器上。
在處理網(wǎng)絡(luò)I/O時,goroutine會集成到網(wǎng)絡(luò)輪詢器的運行時。
Go運行時的線程數(shù)量默認(rèn)為10000。超過這個數(shù)量時,運行時會崩潰。使用runtime/debug包中的方法SetMaxThreads()可以提高線程數(shù)量。
并發(fā)concurrency不是并行parallelism。并行是讓不同的代碼片段同時在不同的物理處理器上執(zhí)行。并行指同時處理很多事情。并發(fā)指同時管理很多事情。
調(diào)用runtime包的方法GOMAXPROCS()可以設(shè)置Go運行時邏輯處理器數(shù)量。
next:for i := 0; i < 10; i++ {for j := 0; j < 10; j++ {if cond {continue next}}}runtime.NumCPU()返回物理處理器數(shù)量。
runtime.Gosched()從線程退出,并放回隊列。
unbuffered := make(chan int) // 無緩沖區(qū)的通道 buffered := make(chan int, 10) // 有緩沖區(qū)的通道無緩沖區(qū)通道要求發(fā)送方和接收方同時準(zhǔn)備好。如果一方?jīng)]有準(zhǔn)備好,另一方會阻塞。
package mainimport ("fmt" )func main() {input := make(chan int)go func() {input <- 1}()foo(input, 10) }func foo(input chan int, end int) {x := <-inputfmt.Println(x)if x >= end {return}go foo(input, end)input <- x + 1 }第七章
import ("os""os/signal" )signalQueue := make(chan os.Signal) signal.Notify(signalQueue, os.Interrupt) # 接收信號 for {if interrupted() {break}// ... }func interrupted() bool {select {case <-signalQueue:signal.Stop(signalQueue) # 停止接收信號return truedefault:return false} } a := []int{1, 2} func add(arr ...int) {b := append(a, arr...) }判斷超時和終端的示例:
interrupt := make(chan os.Signal, 1) complete := make(chan error) timeout := time.After(3 * time.Second)signal.Notify(r.interrupt, os.Interrupt) go func() {complete <- someFunc() }()select { case err := <-complete:return err case <-r.timeout:return "timeout" }每個調(diào)用signal.Notify(signalChan, signum)的隊列,都會收到信號。
第八章
import "log"log.SetPrefix("TRACE: ") log.SetFlags(log.Ldata | log.Llongfile) // Ldate Ltime Llongfile Lmicroseconds Lshortfile // LstdFlags = Ldate | Ltime log.Println("abc") log.Fatalln("abc") log.Panicln("abc")log.New(ioutil.Discard, "TRACE: ", log.LstdFlags|log.Lshortfile) log.New(io.MultiWriter(file, os.Stderr), "ERROR: ", log.LstdFlags|log.Lshortfile)iota關(guān)鍵字為每個常量復(fù)制相同的表達式,并且每次自增1:
const (a = 1 << iota // 1b // 2c // 4 )const (x = iota // 0y // 1z // 2 )第九章
單元測試示例:
import "testing"func TestFoo(t *testing.T) {t.Log("abc")t.Logf("a = %v", 2)t.Errorf("%v", 123)t.Fatal("abc") }測試web服務(wù)示例:
import ("testing""net/http""net/http/httptest" )feed := `<xml ...>`func MockServer() *httptest.Server {return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {w.WriteHeader(200)w.Header().Set("Content-Type", "application/xml")fmt.Fprintln(w, feed)})) }func TestFoo(t *testing.T) {server := mockServer()defer server.Close()resp, err := http.Get(server.URL)if err != nil {t.Fatal(err)}defer resp.Body.Close()// ... }測試web服務(wù)示例:
http.HandleFunc("/some", func(rw http.ResponseWriter, r *http.Request) {// ... })func TestSome(t *testing.T) {req, _ := http.NewRequest("GET", "/some", nil)rw := httptest.NewRecorder()http.DefaultServeMux.ServeHTTP(rw, req) }基準(zhǔn)測試:
func BenchmarkSprintf(b *testing.B) {number := 10b.ResetTimer()for i := 0; i < b.N; i++ {fmt.Sprintf("%d", number)} }修訂記錄
轉(zhuǎn)載于:https://my.oschina.net/u/131191/blog/1505533
總結(jié)
以上是生活随笔為你收集整理的Go语言实战读书笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cocos2dx动作讲解
- 下一篇: Rancher upgrade webh