Go語言技術(shù)特點探究

      網(wǎng)友投稿 826 2022-05-29

      1?【引子】

      前段時間軟件學(xué)院的劉杰珍(340654)給軟件教練們作軟件可信認(rèn)證的相關(guān)介紹時,提到了目前的可信認(rèn)證包括如下的內(nèi)容:

      設(shè)計模式,重構(gòu),面向?qū)ο笤O(shè)計,編程語言高階特性,其中編程語言包括C, C++, Java, Go, Python, Javascript。

      針對以上內(nèi)容,目前已經(jīng)做了:

      ü??C語言技術(shù)特點的總結(jié)《C語言的技術(shù)特點探究》

      ü??代碼重構(gòu)技術(shù)的總結(jié)《代碼重構(gòu)技術(shù)探究》

      本文我們一起來探討和學(xué)習(xí)一下Go語言的技術(shù)特點。先來看個例子:

      package?main

      import?(

      "fmt"

      "time"

      )

      //?要在goroutine中運行的函數(shù)。done通道將被用來通知工作已經(jīng)完成。

      func?worker(done?chan?bool)?{

      fmt.Print("working...")

      time.Sleep(time.Second)

      fmt.Println("done")

      //?通知完成。

      done?<-?true

      }

      func?main()?{

      //?創(chuàng)建一個通道

      done?:=?make(chan?bool,?1)

      go?worker(done)

      //?等待done變?yōu)閠rue

      <-done

      }

      上例中是一個在Go語言中使用goroutine和通道的例子。 其中:

      n??go?關(guān)鍵字是用來啟動一個goroutine

      n??done <- true,?向通道傳值

      n??<-done, 讀取通道值

      2?【概述】

      Go是由RobertGriesemer、RobPike和KenThompson在Google設(shè)計的一種靜態(tài)類型化的、須編譯后才能運行的編程語言。

      Go在語法上類似于C語言,但它具有C語言沒有的優(yōu)勢,如內(nèi)存安全、垃圾回收、結(jié)構(gòu)化的類型和CSP風(fēng)格的并發(fā)性。

      它的域名是golang.org,所以通常被稱為"Golang",但正確的名稱是Go。

      3?【GO的設(shè)計思想】

      Go的設(shè)計受C語言的影響,但更加簡單和安全。該語言包括如下特點:

      ü??采用動態(tài)語言中比較常見的語法和環(huán)境模式:

      ü??可選的簡明變量聲明和通過類型推理進(jìn)行初始化(如果使用x := 0而不是int x= 0;或var x= 0;)。

      ü??快速編譯。

      ü??遠(yuǎn)程包管理(go get)和在線包文檔。

      ü??針對特定問題的獨特方法:

      ü??內(nèi)置的并發(fā)基元:輕量級處理機制(goroutines)、通道和select語句。

      ü??用接口系統(tǒng)代替虛擬繼承,用類型嵌入代替非虛擬繼承。

      ü??默認(rèn)情況下,由一個工具鏈生成靜態(tài)鏈接的原生二進(jìn)制文件,沒有外部依賴關(guān)系。

      ü??希望保持語言規(guī)范足夠簡單,程序員容易掌握。

      3.1????簡潔的語法

      Go的語法包含C語言中保持代碼簡潔性和可讀性的語法特點。

      3.1.1????變量聲明

      引入了一個聯(lián)合聲明/初始化操作符,允許程序員寫出i := 3或s :="Hello, world!",而不需要指定使用的變量類型。

      這與C語言中的int i= 3;?和?const char?*s = "Hello, world!";形成鮮明對比。

      3.1.2????分號隱含

      分號仍然是終止語句,但在行結(jié)束時是隱含的。

      3.1.3????返回多值

      在Go中,一個函數(shù)方法可以返回多個值,返回一個結(jié)果和錯誤err組合對是向調(diào)用者提示錯誤的常規(guī)方式。

      3.1.4????范圍表達(dá)式

      Go的范圍表達(dá)式允許在數(shù)組、動態(tài)數(shù)組、字符串、字典和通道上進(jìn)行簡潔的迭代,在C語言中,有三種循環(huán)來實現(xiàn)這個功能。

      3.2????類型系統(tǒng)

      3.2.1????內(nèi)置的類型

      Go有許多內(nèi)置的類型,包括數(shù)字類型(byte、int64、float32等)、booleans和字符串(string)。

      字符串是不可更改的。

      內(nèi)置的運算符和關(guān)鍵字(而不是函數(shù))提供了串聯(lián)、比較和UTF-8編碼/解碼。

      3.2.2????結(jié)構(gòu)類型

      記錄類型可以用struct關(guān)鍵字定義。

      3.2.3????數(shù)組類型

      對于每個類型T和每個非負(fù)整數(shù)常數(shù)n,都有一個數(shù)組類型,表示為[n]T,因此,不同長度的數(shù)組有不同的類型。

      動態(tài)數(shù)組可以作為"Slice"使用,如對于某類型T,表示為[]T。這些數(shù)組有一個長度和一個容量,容量規(guī)定了何時需要分配新的內(nèi)存來擴(kuò)展數(shù)組。若干個Slice可以共享它們的底層內(nèi)存。

      3.2.4????指針

      所有類型都可以定義指針,?T類型的指針可定義為*T。地址抽取和隱式訪問使用&和*操作符,這跟C語言一樣,或者隱式的通過方法調(diào)用或?qū)傩栽L問使用。

      除了標(biāo)準(zhǔn)庫中的特殊的unsafe.Pointer類型,一般指針沒有指針運算。

      3.2.5????映射類型

      對于一個組合對類型K、V,類型map[K]V是將類型K鍵映射到類型V值的哈希表的類型。

      3.2.6????通道類型

      chan T是一個通道,允許在并發(fā)的Go進(jìn)程之間發(fā)送T類型的值。

      3.2.7????顯式類型

      除了對接口的支持外,Go的類型系統(tǒng)是顯示的:類型關(guān)鍵字可以用來定義一個新的命名類型,它與其他具有相同布局的命名類型(對于結(jié)構(gòu)體來說,相同的成員按相同的順序排列)不同。類型之間的一些轉(zhuǎn)換(如各種整數(shù)類型之間的轉(zhuǎn)換)是預(yù)先定義好的,添加一個新的類型可以定義額外的轉(zhuǎn)換,但命名類型之間的轉(zhuǎn)換必須始終顯式調(diào)用。例如,類型關(guān)鍵字可以用來定義IPv4地址的類型,基于32位無符號整數(shù):

      type?ipv4addr?uint32

      通過這個類型定義,ipv4addr(x)將uint32值x解釋為IP地址。如果簡單地將x分配給類型為ipv4addr的變量將會是一個類型錯誤。

      常量表達(dá)式既可以是類型化的,也可以是?"非類型化的";如果它們所代表的值通過了編譯時的檢查,那么當(dāng)它們被分配給一個類型化的變量時,就會被賦予一個類型。

      3.2.8????函數(shù)類型

      函數(shù)類型由func關(guān)鍵字表示;它們?nèi)?個或更多的參數(shù)并返回0個或更多的值,這些值都是要聲明類型的。

      參數(shù)和返回值決定了一個函數(shù)的類型;比如,func(string, int32)(int, error)就是輸入一個字符串和一個32位有符號的整數(shù),并返回一個有符號的整數(shù)和一個錯誤(內(nèi)置接口類型)的值的函數(shù)類型。

      3.2.9????類型上的方法擴(kuò)展

      任何命名的類型都有一個與之相關(guān)聯(lián)的方法集合。上面的IP地址例子可以用一個檢查其值是否為已知標(biāo)準(zhǔn)的方法來擴(kuò)展:

      //?ZeroBroadcast報告addr是否為255.255.255.255.255。

      func?(addr?ipv4addr)?ZeroBroadcast()?bool?{

      return?addr?==?0xFFFFFFFF

      }

      以上的函數(shù)在ipv4addr上增加了一個方法,但這個方法在uint32上沒有。

      3.2.10?接口系統(tǒng)

      Go提供了兩個功能來取代類繼承。

      首先是嵌入方法,可以看成是一種自動化的構(gòu)成形式或委托代理。

      第二種是接口,它提供了運行時的多態(tài)性。

      接口是一類型,它在Go的類型系統(tǒng)中提供了一種有限的結(jié)構(gòu)類型化形式。

      一個接口類型的對象同時也有另一種類型的定義對應(yīng),這點就像C++對象同時具有基類和派生類的特征一樣。

      Go接口是在Smalltalk編程語言的協(xié)議基礎(chǔ)上設(shè)計的。

      在描述Go接口時使用了鴨式填充這個術(shù)語。

      雖然鴨式填充這個術(shù)語沒有精確的定義,它通常是說這些對象的類型一致性沒有被靜態(tài)檢查。

      接口類型的定義按名稱和類型列出了所需的方法。任何存在與接口類型I的所需方法匹配的函數(shù)的T類型的對象也是類型I的對象。類型T的定義不需要也不能識別類型I。例如,如果Shape、Square和Circle被定義為:

      import?"math"

      type?Shape?interface?{

      Area()?float64

      }

      type?Square?struct?{?//?注:沒有?"實現(xiàn)?"聲明

      side?float64

      }

      func?(sq?Square)?Area()?float64?{?return?sq.side?*?sq.side?}

      type?Circle?struct?{?//?這里也沒有?"實現(xiàn)?"聲明

      radius?float64

      }

      func?(c?Circle)?Area()?float64?{?return?math.Pi?*?math.Pow(c.radius,?2)?}

      一個正方形和一個圓都隱含著一個形狀(Shape)類型,并且可以被分配給一個形狀(Shape)類型的變量。

      Go的接口系統(tǒng)使用了了結(jié)構(gòu)類型。接口也可以嵌入其他接口,其效果是創(chuàng)建一個組合接口,而這個組合接口正是由實現(xiàn)嵌入接口的類型和新定義的接口所增加的方法來滿足的。

      Go標(biāo)準(zhǔn)庫在多個地方使用接口來提供通用性,這包括基于Reader和Writer概念的輸入輸出系統(tǒng)。

      除了通過接口調(diào)用方法,Go還允許通過運行時類型檢查將接口值轉(zhuǎn)換為其他類型。這就是類型斷言和類型切換。

      空接口{}是一個重要的基本情況,因為它可以引用任何類型的選項。它類似于Java或C#中的Object類,可以滿足任何類型,包括像int這樣的內(nèi)置類型。

      使用空接口的代碼不能簡單地在被引用的對象上調(diào)用方法或內(nèi)置操作符,但它可以存儲interface{}值,通過類型斷言或類型切換嘗試將其轉(zhuǎn)換為更有用的類型,或者用Go的reflect包來檢查它。

      因為?interface{}?可以引用任何值,所以它是一種擺脫靜態(tài)類型化限制的有效方式,就像C?語言中的?void*,但在運行時會有額外的類型檢查。

      接口值是使用指向數(shù)據(jù)的指針和第二個指向運行時類型信息的指針來實現(xiàn)的。與Go中其他一些使用指針實現(xiàn)的類型一樣,如果未初始化,接口值是零。

      3.3????程序包系統(tǒng)

      在Go的包系統(tǒng)中,每個包都有一個路徑(如"compress/bzip2 "或"golang.org/x/net/html")和一個名稱(如bzip2或html)。

      對其他包的定義的引用必須始終以其他包的名稱作為前綴,并且只有其他包的大寫的名稱才能被訪問:io.Reader是公開的,但bzip2.reader不是。

      go get命令可以檢索存儲在遠(yuǎn)程資源庫中的包,鼓勵開發(fā)者在開發(fā)包時,在與源資源庫相對應(yīng)的基礎(chǔ)路徑

      (如example.com/user_name/package_name)內(nèi)開發(fā)程序包,從而減少將來在標(biāo)準(zhǔn)庫或其他外部庫中名稱碰撞的可能性。

      有人提議Go引入一個合適的包管理解決方案,類似于CPANfor Perl或Rust的Cargo系統(tǒng)或Node的npm系統(tǒng)。

      3.4????并發(fā):goroutines和通道

      3.4.1????【CSP并發(fā)模式】

      在計算機科學(xué)中,通信順序過程(communicating sequential processes,CSP)是一種描述并發(fā)系統(tǒng)中交互模式的正式語言,它是并發(fā)數(shù)學(xué)理論家族中的一個成員,被稱為過程算法(process algebras),或者說過程計算(process calculate),是基于消息的通道傳遞的數(shù)學(xué)理論。

      CSP在設(shè)計Oceam編程語言時起了很大的影響,同時也影響了Limbo、RaftLib、Go、Crystal和Clojure的core.async等編程語言的設(shè)計。

      CSP最早是由TonyHoare在1978年的一篇論文中描述的,后來有了很大的發(fā)展。

      CSP作為一種工具被實際應(yīng)用于工業(yè)上,用于指定和驗證各種不同系統(tǒng)的并發(fā)功能,如T9000Transputer以及安全的電子商務(wù)系統(tǒng)。

      CSP本身的理論目前也仍然是被積極研究的對象,包括增加其實際適用范圍的工作,如增加可分析的系統(tǒng)規(guī)模。

      Go語言有內(nèi)置的機制和庫支持來編寫并發(fā)程序。并發(fā)不僅指的是CPU的并行性,還指的是異步性處理:讓相對慢的操作,如數(shù)據(jù)庫或網(wǎng)絡(luò)讀取等操作在做其他工作的同時運行,這在基于事件的服務(wù)器中很常見。

      主要的并發(fā)構(gòu)造是goroutine,這是一種輕量級處理類型。一個以go關(guān)鍵字為前綴的函數(shù)調(diào)用會在一個新的goroutine中啟動這個函數(shù)。

      語言規(guī)范并沒有指定如何實現(xiàn)goroutine,但目前的實現(xiàn)將Go進(jìn)程的goroutine復(fù)用到一個較小的操作系統(tǒng)線程集上,類似于Erlang中的調(diào)度。

      雖然一個標(biāo)準(zhǔn)的庫包具有大多數(shù)經(jīng)典的并發(fā)控制結(jié)構(gòu)(mutex鎖等),但Go并發(fā)程序更偏重于通道,它提供了goroutines之間的消息傳功能。

      可選的緩沖區(qū)以FIFO順序存儲消息,允許發(fā)送的goroutines在收到消息之前繼續(xù)進(jìn)行。

      通道是類型化的,所以chan T類型的通道只能用于傳輸T類型的消息。

      特殊語法約定用于對它們進(jìn)行操作;<-ch是一個表達(dá)式,它使執(zhí)行中的goroutine在通道ch上阻塞,直到有一個值進(jìn)來,而ch<- x則是發(fā)送值x(可能阻塞直到另一個goroutine接收到這個值)。

      內(nèi)置的類似于開關(guān)的選擇語句可以用來實現(xiàn)多通道上的非阻塞通信。Go有一個內(nèi)存模型,描述了goroutine必須如何使用通道或其他操作來安全地共享數(shù)據(jù)。

      通道的存在使Go有別于像Erlang這樣的actor模型式的并發(fā)語言,在這種語言中,消息是直接面向actor(對應(yīng)于goroutine)的。在Go中,可以通過在goroutine和通道之間保持一對一的對應(yīng)關(guān)系來,Go語言也允許多個goroutine共享一個通道,或者一個goroutine在多個通道上發(fā)送和接收消息。

      通過這些功能,人們可以構(gòu)建像workerpools、流水線(比如說,在下載文件時,對文件進(jìn)行解壓縮和解析)、帶超時的后臺調(diào)用、對一組服務(wù)的"扇出"并行調(diào)用等并發(fā)構(gòu)造。

      通道也有一些超越進(jìn)程間通信的常規(guī)概念的用途,比如作為一個并發(fā)安全的回收緩沖區(qū)列表,實現(xiàn)coroutines和實現(xiàn)迭代器。

      Go的并發(fā)相關(guān)的結(jié)構(gòu)約定(通道和替代通道輸入)來自于TonyHoare的通信順序進(jìn)程模型。

      不像以前的并發(fā)編程語言,如Occam或Limbo(Go的共同設(shè)計者RobPike曾在此基礎(chǔ)上工作過的語言),Go沒有提供任何內(nèi)置的安全或可驗證的并發(fā)概念。

      雖然在Go中,上述的通信處理模型是推薦使用的,但不是唯一的:一個程序中的所有g(shù)oroutines共享一個單一的地址空間。這意味著可突變對象和指針可以在goroutines之間共享。

      3.5????并行編程的舒適度

      有一項研究比較了一個不熟悉Go語言的老練程序員編寫的程序的大小(以代碼行數(shù)為單位)和速度,以及一個Go專家(來自Google開發(fā)團(tuán)隊)對這些程序的修正,對Chapel、Cilk和IntelTBB做了同樣的研究。

      研究發(fā)現(xiàn),非專家傾向于用每個遞歸中的一條Go語句來寫分解-解決算法,而專家則用每個處理器的一條Go語句來寫分布式工作同步程序。Go專家的程序通常更快,但也更長。

      3.6????條件競賽安全問題

      Goroutine對于如何訪問共享數(shù)據(jù)沒有限制,這使得條件競賽成為可能的問題。

      具體來說,除非程序通過通道或其他方式顯式同步,否則多個goroutine共享讀寫一個內(nèi)存區(qū)域可能會發(fā)生問題。

      此外,Go的內(nèi)部數(shù)據(jù)結(jié)構(gòu),如接口值、動態(tài)數(shù)組頭、哈希表和字符串頭等內(nèi)部數(shù)據(jù)結(jié)構(gòu)也不能幸免于條件競賽,因此在多線程程序中,如果修改這些類型的共享實例沒有同步,就會存在影響類型和內(nèi)存安全的情況。

      3.7????二進(jìn)制生成

      gc工具鏈中的鏈接器默認(rèn)會創(chuàng)建靜態(tài)鏈接的二進(jìn)制文件,因此所有的Go二進(jìn)制文件都包括Go運行所需要的內(nèi)容。

      3.8????舍棄的語言特征

      Go故意省略了其他語言中常見的一些功能,包括繼承、通用編程、斷言、指針運算、隱式類型轉(zhuǎn)換、無標(biāo)記的聯(lián)合和標(biāo)記聯(lián)合。

      3.9????Go風(fēng)格特點

      ·?????????gofmt工具自動規(guī)范了代碼的縮進(jìn)、間距和其他表面級的細(xì)節(jié)。

      ·?????????與Go一起分發(fā)的工具和庫推薦了一些標(biāo)準(zhǔn)的方法,比如API文檔(godoc)、 測試(go test)、構(gòu)建(go build)、包管理(go get)等等。

      ·?????????Go的一些規(guī)則跟其他語言不同,例如禁止循環(huán)依賴、未使用的變量或?qū)搿㈦[式類型轉(zhuǎn)換等。

      ·?????????某些特性的省略(例如,函數(shù)編程的一些捷徑,如map和Java風(fēng)格的try/finally塊)編程風(fēng)格顯式化,具體化,簡單化。

      ·?????????Go團(tuán)隊從第一天開始就發(fā)布了一個Go的語法使用集合,后來還收集了一些代碼的評論,講座和官方博客文章,來推廣Go的風(fēng)格和編碼理念。

      4? ?Go的工具

      主要的Go發(fā)行版包括構(gòu)建、測試和分析代碼的工具。

      ü??go build,它只使用源文件中的信息來構(gòu)建Go二進(jìn)制文件,不使用單獨的makefiles。

      ü??gotest,用于單元測試和微基準(zhǔn)

      ü??go fmt,用于格式化代碼

      ü??go get,用于檢索和安裝遠(yuǎn)程包。

      ü??go vet,靜態(tài)分析器,查找代碼中的潛在錯誤。

      ü??go run,構(gòu)建和執(zhí)行代碼的快捷方式

      ü??godoc,用于顯示文檔或通過HTTP

      ü??gorename,用于以類型安全的方式重命名變量、函數(shù)等。

      ü??go generate,一個標(biāo)準(zhǔn)的調(diào)用代碼生成器的方法。

      它還包括分析和調(diào)試支持、運行時診斷(例如,跟蹤垃圾收集暫停)和條件競賽測試器。

      第三方工具的生態(tài)系統(tǒng)增強了標(biāo)準(zhǔn)的發(fā)布系統(tǒng),如:

      gocode,它可以在許多文本編輯器中自動完成代碼,

      goimports(由Go團(tuán)隊成員提供),它可以根據(jù)需要自動添加/刪除包導(dǎo)入,以及errcheck,它可以檢測可能無意中被忽略的錯誤代碼。

      5???編輯環(huán)境

      流行的Go代碼工具:

      ü??GoLand:JetBrains公司的IDE。

      ü??VisualStudio Code

      ü??LiteIDE:一個"簡單、開源、跨平臺的GoIDE"

      ü??Vim:用戶可以安裝插件:

      ü??vim-go

      Go語言技術(shù)特點探究

      6? ?應(yīng)用案例

      用Go編寫的一些著名的開源應(yīng)用包括:

      ü??Caddy,一個開源的HTTP/2web服務(wù)器,具有自動HTTPS功能。

      ü??CockroachDB,一個開源的、可生存的、強一致性、可擴(kuò)展的SQL數(shù)據(jù)庫。

      ü??Docker,一套用于部署Linux容器的工具。

      ü??Ethereum,以太幣虛擬機區(qū)塊鏈的Go-Ethereum實現(xiàn)。

      ü??Hugo,一個靜態(tài)網(wǎng)站生成器

      ü??InfluxDB,一個專門用于處理高可用性和高性能要求的時間序列數(shù)據(jù)的開源數(shù)據(jù)庫。

      ü??InterPlanetaryFile System,一個可內(nèi)容尋址、點對點的超媒體協(xié)議。

      ü??Juju,由UbuntuLinux的包裝商Canonical公司推出的服務(wù)協(xié)調(diào)工具。

      ü??Kubernetes容器管理系統(tǒng)

      ü??lnd,比特幣閃電網(wǎng)絡(luò)的實現(xiàn)。

      ü??Mattermost,一個團(tuán)隊聊天系統(tǒng)

      ü??NATSMessaging,是一個開源的消息傳遞系統(tǒng),其核心設(shè)計原則是性能、可擴(kuò)展性和易用性。

      ü??OpenShift,云計算服務(wù)平臺

      ü??Snappy,一個由Canonical開發(fā)的UbuntuTouch軟件包管理器。

      ü??Syncthing,一個開源的文件同步客戶端/服務(wù)器應(yīng)用程序。

      ü??Terraform,是HashiCorp公司的一款開源的多云基礎(chǔ)設(shè)施配置工具。

      ü??其他使用Go的知名公司和網(wǎng)站包括:

      ü??Cacoo,使用Go和gRPC渲染用戶儀表板頁面和微服務(wù)。

      ü??Chango,程序化廣告公司,在其實時競價系統(tǒng)中使用Go。

      ü??CloudFoundry,平臺即服務(wù)系統(tǒng)

      ü??Cloudflare,三角編碼代理Railgun,分布式DNS服務(wù),以及密碼學(xué)、日志、流處理和訪問SPDY網(wǎng)站的工具。

      ü??容器Linux(原CoreOS),是一個基于Linux的操作系統(tǒng),使用Docker容器和rkt容器。

      ü??Couchbase、Couchbase服務(wù)器內(nèi)的查詢和索引服務(wù)。

      ü??Dropbox,將部分關(guān)鍵組件從Python遷移到了Go。

      ü??谷歌,許多項目,特別是下載服務(wù)器dl.google.com。

      ü??Heroku,Doozer,一個提供鎖具服務(wù)的公司

      ü??HyperledgerFabric,一個開源的企業(yè)級分布式分類賬項目。

      ü??MongoDB,管理MongoDB實例的工具。

      ü??Netflix的服務(wù)器架構(gòu)的兩個部分。

      ü??Nutanix,用于其企業(yè)云操作系統(tǒng)中的各種微服務(wù)。

      ü??Plug.dj,一個互動式在線社交音樂流媒體網(wǎng)站。

      ü??SendGrid是一家位于科羅拉多州博爾德市的事務(wù)性電子郵件發(fā)送和管理服務(wù)。

      ü??SoundCloud,"幾十個系統(tǒng)"

      ü??Splice,其在線音樂協(xié)作平臺的整個后端(API和解析器)。

      ü??ThoughtWorks,持續(xù)傳遞和即時信息的工具和應(yīng)用(CoyIM)。

      ü??Twitch,他們基于IRC的聊天系統(tǒng)(從Python移植過來的)。

      ü??Uber,處理大量基于地理信息的查詢。

      7??代碼示例

      7.1????Hello World

      package?main

      import?"fmt"

      func?main()?{

      fmt.Println("Hello,?world!")

      }

      7.2????并發(fā)

      package?main

      import?(

      "fmt"

      "time"

      )

      func?readword(ch?chan?string)?{

      fmt.Println("Type?a?word,?then?hit?Enter.")

      var?word?string

      fmt.Scanf("%s",?&word)

      ch?<-?word

      }

      func?timeout(t?chan?bool)?{

      time.Sleep(5?*?time.Second)

      t?<-?false

      }

      func?main()?{

      t?:=?make(chan?bool)

      go?timeout(t)

      ch?:=?make(chan?string)

      go?readword(ch)

      select?{

      case?word?:=?<-ch:

      fmt.Println("Received",?word)

      case?<-t:

      fmt.Println("Timeout.")

      }

      }

      7.3????代碼測試

      沒有測試的代碼是不完整的,因此我們需要看看代碼測試部分的編寫。

      代碼:

      func?ExtractUsername(email?string)?string?{

      at?:=?strings.Index(email,?"@")

      return?email[:at]

      }

      測試案例:

      func?TestExtractUsername(t?*testing.T)?{

      type?args?struct?{

      email?string

      }

      tests?:=?[]struct?{

      name?string

      args?args

      want?string

      }{

      {"withoutDot",?args{email:?"r@google.com"},?"r"},

      {"withDot",?args{email:?"jonh.smith@example.com"},?"jonh.smith"},

      }

      for?_,?tt?:=?range?tests?{

      t.Run(tt.name,?func(t?*testing.T)?{

      if?got?:=?ExtractUsername(tt.args.email);?got?!=?tt.want?{

      t.Errorf("ExtractUsername()?=?%v,?want?%v",?got,?tt.want)

      }

      })

      }

      }

      7.4????創(chuàng)建后端服務(wù)

      接下來我寫一個例子創(chuàng)建REST API后端服務(wù):

      我們的服務(wù)提供如下的API:

      ###

      GET?http://localhost:10000/

      ###

      GET?http://localhost:10000/all

      ###

      GET?http://localhost:10000/article/1

      ###

      POST?http://localhost:10000/article?HTTP/1.1

      {

      "Id":?"3",

      "Title":?"Hello?2",

      "desc":?"Article?Description",

      "content":?"Article?Content"

      }

      ###

      PUT?http://localhost:10000/article?HTTP/1.1

      {

      "Id":?"2",

      "Title":?"Hello?2?Update",

      "desc":?"Article?Description?Update",

      "content":?"Article?Content?Update"

      }

      完整代碼:

      package?main

      import?(

      "encoding/json"

      "fmt"

      "io/ioutil"

      "log"

      "net/http"

      "github.com/gorilla/mux"

      )

      type?Article?struct?{

      Id??????string?`json:"Id"`

      Title???string?`json:"Title"`

      Desc????string?`json:"desc"`

      Content?string?`json:"content"`

      }

      var?MapArticles?map[string]Article

      var?Articles?[]Article

      func?returnAllArticles(w?http.ResponseWriter,?r?*http.Request)?{

      fmt.Println("Endpoint?Hit:?returnAllArticles")

      json.NewEncoder(w).Encode(Articles)

      }

      func?homePage(w?http.ResponseWriter,?r?*http.Request)?{

      fmt.Fprintf(w,?"Welcome?to?the?HomePage!")

      fmt.Println("Endpoint?Hit:?homePage")

      }

      func?createNewArticle(w?http.ResponseWriter,?r?*http.Request)?{

      reqBody,?_?:=?ioutil.ReadAll(r.Body)

      var?article?Article

      json.Unmarshal(reqBody,?&article)

      Articles?=?append(Articles,?article)

      MapArticles[article.Id]?=?article

      json.NewEncoder(w).Encode(article)

      }

      func?updateArticle(w?http.ResponseWriter,?r?*http.Request)?{

      reqBody,?_?:=?ioutil.ReadAll(r.Body)

      var?article?Article

      json.Unmarshal(reqBody,?&article)

      found?:=?false

      for?index,?v?:=?range?Articles?{

      if?v.Id?==?article.Id?{

      //?Found!

      found?=?true

      Articles[index]?=?article

      }

      }

      if?!found?{

      Articles?=?append(Articles,?article)

      }

      MapArticles[article.Id]?=?article

      json.NewEncoder(w).Encode(article)

      }

      func?returnSingleArticle(w?http.ResponseWriter,?r?*http.Request)?{

      vars?:=?mux.Vars(r)

      key?:=?vars["id"]

      fmt.Fprintf(w,?"Key:?%s?\n",?key)

      json.NewEncoder(w).Encode(MapArticles[key])

      }

      func?handleRequests()?{

      myRouter?:=?mux.NewRouter().StrictSlash(true)

      myRouter.HandleFunc("/",?homePage)

      myRouter.HandleFunc("/all",?returnAllArticles)

      myRouter.HandleFunc("/article",?createNewArticle).Methods("POST")

      myRouter.HandleFunc("/article",?updateArticle).Methods("PUT")

      myRouter.HandleFunc("/article/{id}",?returnSingleArticle)

      log.Fatal(http.ListenAndServe(":10000",?myRouter))

      }

      func?main()?{

      fmt.Println("Rest?API?is?ready?...")

      MapArticles?=?make(map[string]Article)

      Articles?=?[]Article{

      Article{Id:?"1",?Title:?"Hello",?Desc:?"Article?Description",?Content:?"Article?Content"},

      Article{Id:?"2",?Title:?"Hello?2",?Desc:?"Article?Description",?Content:?"Article?Content"},

      }

      for?_,?a?:=?range?Articles?{

      MapArticles[a.Id]?=?a

      }

      handleRequests()

      }

      調(diào)用添加,更新API以后返回所有數(shù)據(jù)的測試結(jié)果:

      8???褒貶不一

      8.1????贊揚

      MicheleSimionato對Go大加贊揚:

      ü??接口系統(tǒng)簡潔,并刻意省略了繼承。

      EngineYard的DaveAstels寫道:

      ü??Go是非常容易上手的。很少的基本語言概念,語法也很干凈,設(shè)計得很清晰。Go目前還是實驗性的,還有些地方比較粗糙。

      2009年,Go被TIOBE編程社區(qū)指數(shù)評選為年度最佳編程語言。

      到2010年1月,Go的排名達(dá)到了第13位,超過了Pascal等成熟的語言。

      但到了2015年6月,它的排名跌至第50位以下,低于COBOL和Fortran。

      但截至2017年1月,它的排名又飆升至第13位,顯示出它的普及率和采用率有了顯著的增長。

      Go被評為2016年TIOBE年度最佳編程語言。

      BruceEckel曾表示:

      ü??C++的復(fù)雜性(在新的C++中甚至增加了更多的復(fù)雜性),以及由此帶來的對生產(chǎn)力的影響,已經(jīng)沒有任何理由繼續(xù)使用C++了。C++程序員為了克服C語言的一些問題而做出的增強初衷目前已經(jīng)沒有了意義,而Go此時顯得更有意義。

      2011年一位Google工程師R.Hundt對Go語言及其GC實現(xiàn)與C++(GCC)、Java和Scala的對比評估發(fā)現(xiàn)。

      ü??Go提供了有趣的語言特性,這也使得Go語言有了簡潔、標(biāo)準(zhǔn)化的特征。這種語言的編譯器還不成熟,這在性能和二進(jìn)制大小上都有體現(xiàn)。

      這一評價收到了Go開發(fā)團(tuán)隊的快速反應(yīng)。

      IanLance Taylor因為Hundt的評論改進(jìn)了Go代碼;

      RussCox隨后對Go代碼以及C++代碼進(jìn)行了優(yōu)化,并讓Go代碼的運行速度比C++略快,比評論中使用的代碼性能快了一個數(shù)量級以上。

      8.2????命名爭議

      2009年11月10日,也就是Go!編程語言全面發(fā)布的當(dāng)天,Go!編程語言的開發(fā)者FrancisMcCabe(注意是感嘆號)要求更改Google的語言名稱,以避免與他花了10年時間開發(fā)的語言混淆。

      McCabe表示了對谷歌這個'大塊頭'最終會碾壓他"的擔(dān)憂,這種擔(dān)憂引起了120多名開發(fā)者的共鳴,他們在Google官方的問題線程上評論說他們應(yīng)該改名,有些人甚至說這個問題違背了Google的座右銘:"不要作惡。"

      2010年10月12日,谷歌開發(fā)者RussCox關(guān)閉了這個問題,自定義狀態(tài)為"不幸",并附上了以下評論:

      "有很多計算產(chǎn)品和服務(wù)都被命名為Go。在我們發(fā)布以來的11個月里,這兩種語言的混淆度極低。"

      8.3????【批評】

      Go的批評家們的觀點:

      ü??通用程序設(shè)計缺乏參數(shù)多態(tài)性,導(dǎo)致代碼重復(fù)或不安全的類型轉(zhuǎn)換以及擾亂流程的隨意性。

      ü??Go的nil,加上代數(shù)類型的缺失,導(dǎo)致故障處理和基本問題的避免很困難。

      ü??Go不允許在當(dāng)前行中出現(xiàn)開局括號,這就迫使所有的Go程序員必須使用相同的括號樣式。

      9? ?【小結(jié)】

      本文從Go的語法,類型系統(tǒng),編碼風(fēng)格,語言工具,編碼工具和使用案例等幾方面對Go語言進(jìn)行了學(xué)習(xí)和探討,希望可以拋磚引玉,對Go語言感興趣的同仁有所裨益。

      歡迎討論。

      10?【更多文章】

      https://en.wikipedia.org/wiki/Go_(programming_language)

      Jet Ding文章歸類索引表

      軟件開發(fā) Go 代碼檢查 CodeCheck

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:人工錄入圖片文字信息行不通!OCR識別工具更方便
      下一篇:Google Doc 更新一個文檔 替換多個變量
      相關(guān)文章
      亚洲国产香蕉人人爽成AV片久久 | 久久精品国产亚洲香蕉| 亚洲AV无码一区二区大桥未久| 亚洲日本国产乱码va在线观看| 国产成人综合亚洲亚洲国产第一页 | 亚洲性日韩精品国产一区二区| 久久亚洲中文无码咪咪爱| 亚洲精品宾馆在线精品酒店| 亚洲欧美成人av在线观看| 亚洲色在线无码国产精品不卡| 99999久久久久久亚洲| 亚洲字幕AV一区二区三区四区| 亚洲av片不卡无码久久| 亚洲伦理一二三四| 亚洲AV无码一区二区三区人| 色偷偷亚洲女人天堂观看欧| 亚洲日本人成中文字幕| 中文有码亚洲制服av片| 亚洲欧美日韩中文字幕一区二区三区 | 亚洲国产av高清无码| 亚洲喷奶水中文字幕电影| 亚洲人成网站18禁止久久影院| 亚洲av片不卡无码久久| 亚洲精品第一综合99久久| 亚洲欧美日韩中文无线码| 日韩亚洲综合精品国产| 亚洲第一黄色网址| 一本久久a久久精品亚洲| 亚洲精品无码不卡在线播放HE| 亚洲成色www久久网站夜月| 亚洲国产精品国自产电影| 91亚洲va在线天线va天堂va国产| 久久久久亚洲AV无码专区首JN| 亚洲精品午夜视频| 亚洲天堂2016| 国产亚洲综合久久| 中文字幕亚洲电影| 亚洲va久久久噜噜噜久久| 亚洲精品视频观看| 亚洲中文字幕久久无码| 精品韩国亚洲av无码不卡区|