GO語言使用的示例分析,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
創(chuàng)新互聯(lián)建站不只是一家網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司;我們對營銷、技術(shù)、服務(wù)都有自己獨特見解,公司采取“創(chuàng)意+綜合+營銷”一體化的方式為您提供更專業(yè)的服務(wù)!我們經(jīng)歷的每一步也許不一定是最完美的,但每一步都有值得深思的意義。我們珍視每一份信任,關(guān)注我們的做網(wǎng)站、成都網(wǎng)站制作質(zhì)量和服務(wù)品質(zhì),在得到用戶滿意的同時,也能得到同行業(yè)的專業(yè)認(rèn)可,能夠為行業(yè)創(chuàng)新發(fā)展助力。未來將繼續(xù)專注于技術(shù)創(chuàng)新,服務(wù)升級,滿足企業(yè)一站式成都全網(wǎng)營銷需求,讓再小的成都品牌網(wǎng)站建設(shè)也能產(chǎn)生價值!
Francesc (@francesc) 是 Go 核心團隊的一員, 是提倡 Google Cloud 平臺的開發(fā)者. 他是一個編程語言的愛好者, Google的技術(shù)指導(dǎo)大師, Go tour的創(chuàng)造者之一. 這個討論的靈感來自于另一個 Raquel Vélez 在 JSConf. Slides 的討論,這個討論已經(jīng)發(fā)到了這里.
Sourcegraph 是下一代編程協(xié)作工具, 用于搜索, 探索, 和審查代碼. 我們參加GopherCon India 來分享我們是怎樣使用 Go 并學(xué)習(xí)別人是怎樣使用它的, 對配合liveblog的這次討論我們深感榮幸.
作為Go團隊的開發(fā)者之一,F(xiàn)rancesc可能比世界上其他人接觸到的Go語言程序員都要多。正因為有了這樣的有利條件,他把Go語言的學(xué)習(xí)過程劃分為5個階段。
這些階段對于其他語言的學(xué)習(xí)也是成立的。理解自己處于哪個階段,可以幫助你找到提高自己的最有效的方法,也可以避免每個階段學(xué)習(xí)過程中的常見陷阱。
第一階段: 菜逼
菜鳥在這個階段使用Go去創(chuàng)建一些小項目或者玩具項目。他們應(yīng)該會利用到Go tour, Go playground, Go文檔, 和郵件列表(golang-nuts).
func main() { fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))}
這是Go語言寫的簡單例子,這個代碼段來自golang/example代碼庫里面的 hello.go 。 點擊就可以查看完整代碼擼。
一項重要的技能,新人應(yīng)該試著學(xué)習(xí)如何正確提問。很多新人在郵件列表里面這樣說“嘿,這報錯了”,這并沒有提供足夠的信息,讓別人能理解并幫助他們解決問題。別人看到的是一個粘貼了幾百行的代碼的帖子,并沒有花費精力來重點說明所遇到的問題。
所以, 應(yīng)該盡量避免直接粘貼代碼到論壇。而應(yīng)該使用可以編輯并且可以在瀏覽器中直接運行的Go playground的“分享”按鈕鏈接到代碼片段。
Phase 2: the explorer
探索者已經(jīng)可以使用Go寫一些小的軟件,但有時仍然會有些迷茫。他們可能不完全明白怎么使用Go的高級特性,比如通道。雖然他們還有很多東西要學(xué)習(xí),但已掌握的足夠做一些有用的事情了!他們開始對Go的潛能有感覺了,并對它們能使用Go創(chuàng)建的東西感到興奮。
在探索階段通常會經(jīng)歷兩個步驟。第一,膨脹的預(yù)期達到頂點,你覺得可以用Go做所有的事情,但還并不能明白或領(lǐng)悟到Go的真諦。你大概會用所熟悉的語言的模式和慣用語來寫Go代碼,但對于什么是地道的Go,還沒有比較強烈的感覺。你開始嘗試著手干這樣的事情--“遷移架構(gòu)X,從Y語言到Go語言”。
到達預(yù)期膨脹的頂點之后,你會遇到理想幻滅的低谷。你開始想念語言Y的特性X,此時你還沒有完全的掌握地道的Go。你還在用其他編程語言的風(fēng)格來寫Go語言的程序,你甚至開始覺得沮喪。你可能在大量使用reflect和unsafe這兩個包,但這不是地道的Go。地道的Go不會使用那些魔法一樣的東西。
這個探索階段產(chǎn)生的項目的一個很好的例子就是Martini Web框架。Martini是一個Go語言的早期Web框架,它從Ruby的Web框架當(dāng)中吸收了很多思想(比如依賴注入)。最初,這個框架在社區(qū)中引起了強烈的反響,但是它逐漸在性能和可調(diào)試性上受到了一些批評。Martini框架的作者Jeremy Saenz積極響應(yīng)這些來自Go社區(qū)的反饋,寫了一個更加符合Go語言規(guī)范的庫Negroni
func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed. logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) logger.Fatalln(http.ListenAndServe(addr, m))}
來自Martini框架的交互式代碼片段,它是不地道的Go的例子。注意用反射包實現(xiàn)的依賴注入
func TestNegroniServeHTTP(t *testing.T) { result := "" response := httptest.NewRecorder() n := New() n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "foo" next(rw, r) result += "ban" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bar" next(rw, r) result += "baz" })) n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { result += "bat" rw.WriteHeader(http.StatusBadRequest) })) n.ServeHTTP(response, (*http.Request)(nil)) expect(t, result, "foobarbatbazban") expect(t, response.Code, http.StatusBadRequest)}
來自Negroni庫的交互式代碼片段,它是地道的Go的例子
其他語言在提供一些核心功能,比如HTTP處理的時候,往往需要依賴第三方庫。但是Go語言在這一點上很不同,它的標(biāo)準(zhǔn)庫非常強大。如果你認(rèn)為Go標(biāo)準(zhǔn)庫沒有強大到可以做你想做的事情,那么我說你錯了。Go語言標(biāo)準(zhǔn)庫難以置信的強大,值得你花時間閱讀它的代碼,學(xué)習(xí)它實現(xiàn)的模式。
func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}
Go標(biāo)準(zhǔn)庫中的ListenAndServe函數(shù)片段。如果你寫過Go程序,你可能已經(jīng)調(diào)用過這個函數(shù)很多次了,但是你曾經(jīng)花時間看過它的實現(xiàn)么?去點擊上面的代碼片段吧。
幻滅的低谷中的幻滅感來自于這樣的事實:你還在用其他語言的模式來想問題,而且你還沒有完全探索過Go能提供給你什么。下面是一些好玩的事情,你可以做一下來打破困境,進一步探索這門語言中好玩的事。
go generate
現(xiàn)在來看看go generate。go generate是一個你可以用來自動自成Go代碼的命令。你可以結(jié)合例如jsonenums(一個用于為枚舉類型自動生成JSON編組樣板代碼的類庫)這樣的元編程來使用go generate快速自動實現(xiàn)重復(fù)乏味代碼的編寫。在Go標(biāo)準(zhǔn)類庫里面已經(jīng)有大量可以用于解析AST的接口,而AST使得編寫元編程工具更簡單,更容易。在會議上,有另外兩次討論(Go語言中的元編程實踐和擁抱標(biāo)準(zhǔn)類庫)談及到了這一點。
func main() { flag.Parse() if len(*typeNames) == 0 { log.Fatalf("the flag -type must be set") } types := strings.Split(*typeNames, ",") // Only one directory at a time can be processed, and the default is ".". dir := "." if args := flag.Args(); len(args) == 1 { dir = args[0] } else if len(args) > 1 { log.Fatalf("only one directory at a time") } pkg, err := parser.ParsePackage(dir, *outputSuffix+".go") if err != nil { log.Fatalf("parsing package: %v", err) } var analysis = struct { Command string PackageName string TypesAndValues map[string][]string }{ Command: strings.Join(os.Args[1:], " "), PackageName: pkg.Name, TypesAndValues: make(map[string][]string), } // Run generate for each type. for _, typeName := range types { values, err := pkg.ValuesOfType(typeName) if err != nil { log.Fatalf("finding values for type %v: %v", typeName, err) } analysis.TypesAndValues[typeName] = values var buf bytes.Buffer if err := generatedTmpl.Execute(&buf, analysis); err != nil { log.Fatalf("generating code: %v", err) } src, err := format.Source(buf.Bytes()) if err != nil { // Should never happen, but can arise when developing this code. // The user can compile the output to see the error. log.Printf("warning: internal error: invalid Go generated: %s", err) log.Printf("warning: compile the package to analyze the error") src = buf.Bytes() } output := strings.ToLower(typeName + *outputSuffix + ".go") outputPath := filepath.Join(dir, output) if err := ioutil.WriteFile(outputPath, src, 0644); err != nil { log.Fatalf("writing output: %s", err) } }}
一段互動的片段演示了如何編寫jsonenums命令。
OpenGL
許多人使用Go作web服務(wù),但是你知道你也可以用Go寫出很cool的圖形應(yīng)用嗎?查看Go在OpenGL中的捆綁。
func main() { glfw.SetErrorCallback(errorCallback) if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate() window, err := glfw.CreateWindow(Width, Height, Title, nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() glfw.SwapInterval(1) gl.Init() if err := initScene(); err != nil { fmt.Fprintf(os.Stderr, "init: %s\n", err) return } defer destroyScene() for !window.ShouldClose() { drawScene() window.SwapBuffers() glfw.PollEvents() }}
交互式的片段正說明Go的OpenGL捆綁能制作Gopher cube。點擊函數(shù)或方法名去探索。
黑客馬拉松和挑戰(zhàn)
你也可以觀看挑戰(zhàn)和黑客馬拉松,類似Gopher Gala和Go Challenge。在過去,來自世界各地的程序員一起挑戰(zhàn)一些真實的酷項目,你可以從中獲取靈感。
第三階段: 老手
作為一個老手,這意味著你可以解決很多Go語言中你關(guān)心的問題。新的需要解決的問題會帶來新的疑問,經(jīng)過試錯,你學(xué)會了在這門語言中什么是可以做的,什么是不能做的。此時,你已經(jīng)對這門語言的習(xí)慣和模式有了一個堅實的理解。你可以非常高效地工作,寫出可讀,文檔完善,可維護的代碼。
成為老手的一個很好的方法就是在大項目上工作。如果你自己有一個項目的想法,開始動手去做吧(當(dāng)然你要確定它并不是已經(jīng)存在了)。大多數(shù)人也許并沒有一個很大的項目的想法,所以他們可以對已經(jīng)存在的項目做出貢獻。Go語言已經(jīng)有很多大型項目,而且它們正在被廣泛使用,比如Docker, Kubernetes和Go本身。可以看看這個項目列表
func (cli *DockerCli) CmdRestart(args ...string) error { cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true) nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container.") cmd.Require(flag.Min, 1) utils.ParseFlags(cmd, args, true) v := url.Values{} v.Set("t", strconv.Itoa(*nSeconds)) var encounteredError error for _, name := range cmd.Args() { _, _, err := readBody(cli.call("POST", "/containers/"+name+"/restart?"+v.Encode(), nil, false)) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to restart one or more containers") } else { fmt.Fprintf(cli.out, "%s\n", name) } } return encounteredError}
Docker項目的交互式代碼片段。點擊函數(shù)名,開始探索之旅吧。
老手應(yīng)該對Go生態(tài)系統(tǒng)的工具有一個很強的掌握,因為這些工具真的提高生產(chǎn)效率。你應(yīng)該了解go generate,go vet,go test-race, 和gofmt/goimports/goreturns。你應(yīng)該使用go fmt,因為它會自動把你的代碼按照Go社區(qū)的風(fēng)格標(biāo)準(zhǔn)來格式化。goimports可以做同樣的事情,而且還會添加丟失的imports。goretures不光做了前面所說的事情,還可以在返回表達式添加丟失的錯誤,這是大家都討厭的地方。
在老手階段,你一定要開始做code review。code review的意義并不是要修改或者找到錯誤(那是測試人員做的事情)。code review可以幫助維持統(tǒng)一的編程風(fēng)格,提高軟件的總體質(zhì)量,還可以在別人的反饋中提高你自己的編程技術(shù)。幾乎所有的大型開源項目都對每一個提交做code review。
下面是一個從人類的反饋當(dāng)中學(xué)習(xí)的例子:Google的Go團隊以前都在main函數(shù)的外面聲明命令行標(biāo)記。在去年的GopherCon會議上,F(xiàn)rancesc遇到了SoundCloud公司的Peter Bourgon(@peterbourgon)。Peter Bourgon說在SoundCloud,他們都在main函數(shù)內(nèi)部聲明標(biāo)記,這樣他們不會錯誤地在外部使用標(biāo)記。Francesc現(xiàn)在認(rèn)為這是最佳實踐。
第四階段:專家
作為一個專家,你很好地了解了語言的哲學(xué)思想。對于Go語言的特性,你知道何時應(yīng)該使用,何時不應(yīng)該使用。例如,Jeremy Saenz在dotGo風(fēng)暴討論中談?wù)摰搅撕螘r不該使用接口。
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call { call := new(Call) call.ServiceMethod = serviceMethod call.Args = args call.Reply = reply if done == nil { done = make(chan *Call, 10) // buffered. } else { // If caller passes done != nil, it must arrange that // done has enough buffer for the number of simultaneous // RPCs that will be using that channel. If the channel // is totally unbuffered, it's best not to run at all. if cap(done) == 0 { log.Panic("rpc: done channel is unbuffered") } } call.Done = done client.send(call) return call}
來自標(biāo)準(zhǔn)類庫的一小塊交互代碼片段使用了頻道。理解標(biāo)準(zhǔn)類庫里面的模式背后的決策原因是成為一個專家必經(jīng)之路。
但是不要成為只局限于單一語言的專家。跟其他任何語言一樣,Go僅僅只是一個工具。你還應(yīng)該去探索其他語言,并且學(xué)習(xí)他們的模式和風(fēng)格。Francesc從他使用Go的經(jīng)驗中找到了編寫JavaScript的啟發(fā)。他還喜歡重點關(guān)注于不可變性和致力于避免易變性的Haskell語言,并從中獲得了如何編寫Go代碼的靈感。
布道者
作為一個布道者,你分享自己的知識,傳授你學(xué)會的和你提出的最佳實踐。你可以分享自己對Go喜歡或者不喜歡的地方。全世界各地都有Go會議,找到離你最近的。
你可以在任何一個階段成為布道者,不要等到你成為這個領(lǐng)域的專家的時候才發(fā)出自己的聲音。在你學(xué)習(xí)Go的任何一個階段,提出問題,結(jié)合你的經(jīng)驗給出反饋,不要羞于提出自己不喜歡的地方。你提出的反饋可以幫助社區(qū)改善做事情的方法,也可能改變你自己對編程的看法。
func main() { httpAddr := flag.String("http", "127.0.0.1:3999", "HTTP service address (e.g., '127.0.0.1:3999')") originHost := flag.String("orighost", "", "host component of web origin URL (e.g., 'localhost')") flag.StringVar(&basePath, "base", "", "base path for slide template and static resources") flag.BoolVar(&present.PlayEnabled, "play", true, "enable playground (permit execution of arbitrary user code)") nativeClient := flag.Bool("nacl", false, "use Native Client environment playground (prevents non-Go code execution)") flag.Parse() if basePath == "" { p, err := build.Default.Import(basePkg, "", build.FindOnly) if err != nil { fmt.Fprintf(os.Stderr, "Couldn't find gopresent files: %v\n", err) fmt.Fprintf(os.Stderr, basePathMessage, basePkg) os.Exit(1) } basePath = p.Dir } err := initTemplates(basePath) if err != nil { log.Fatalf("Failed to parse templates: %v", err) } ln, err := net.Listen("tcp", *httpAddr) if err != nil { log.Fatal(err) } defer ln.Close() _, port, err := net.SplitHostPort(ln.Addr().String()) if err != nil { log.Fatal(err) } origin := &url.URL{Scheme: "http"} if *originHost != "" { origin.Host = net.JoinHostPort(*originHost, port) } else if ln.Addr().(*net.TCPAddr).IP.IsUnspecified() { name, _ := os.Hostname() origin.Host = net.JoinHostPort(name, port) } else { reqHost, reqPort, err := net.SplitHostPort(*httpAddr) if err != nil { log.Fatal(err) } if reqPort == "0" { origin.Host = net.JoinHostPort(reqHost, port) } else { origin.Host = *httpAddr } } if present.PlayEnabled { if *nativeClient { socket.RunScripts = false socket.Environ = func() []string { if runtime.GOARCH == "amd64" { return environ("GOOS=nacl", "GOARCH=amd64p32") } return environ("GOOS=nacl") } } playScript(basePath, "SocketTransport") http.Handle("/socket", socket.NewHandler(origin)) } http.Handle("/static/", http.FileServer(http.Dir(basePath))) if !ln.Addr().(*net.TCPAddr).IP.IsLoopback() && present.PlayEnabled && !*nativeClient { log.Print(localhostWarning) } log.Printf("Open your web browser and visit %s", origin.String()) log.Fatal(http.Serve(ln, nil))
流行的present命令的main函數(shù),很多Go的用戶使用它來制作幻燈片。許多演講者修改了這個模塊來滿足自己的需要。
Q&A
問:在GO語言中,我所懷念的一項功能是一個好的調(diào)試器。
答:我們正在做了,不只是調(diào)試器,我們還會提供一個更好的總體監(jiān)視工具可以讓你在程序運行時更好地洞察程序在干什么(顯示出所有正在運行的goroutine的狀態(tài))。在GO 1.5中探索它吧。
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。
分享標(biāo)題:GO語言使用的示例分析
URL地址:http://www.rwnh.cn/article20/jscdjo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、ChatGPT、做網(wǎng)站、企業(yè)建站、網(wǎng)站建設(shè)、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)