一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

GO 語(yǔ)言學(xué)習(xí)的五個(gè)階段(帶例子)

 codingparty 2015-03-07

Francesc ( @francesc ) 是 Go 核心團(tuán)隊(duì)的一員, 是提倡 Google Cloud 平臺(tái)的開發(fā)者. 他是一個(gè)編程語(yǔ)言的愛好者, Google的技術(shù)指導(dǎo)大師, Go tour的創(chuàng)造者之一. 這個(gè)討論的靈感來(lái)自于另一個(gè) Raquel Vélez 在 JSConf. Slides 討論 ,這個(gè) 討論 已經(jīng)發(fā)到了 這里 .

Sourcegraph 是下一代編程協(xié)作工具, 用于搜索, 探索, 和審查代碼. 我們參加GopherCon India 來(lái)分享我們是怎樣使用 Go 并學(xué)習(xí)別人是怎樣使用它的, 對(duì)配合liveblog的這次討論我們深感榮幸.

作為Go團(tuán)隊(duì)的開發(fā)者之一,F(xiàn)rancesc可能比世界上其他人接觸到的Go語(yǔ)言程序員都要多。正因?yàn)橛辛诉@樣的有利條件,他把Go語(yǔ)言的學(xué)習(xí)過(guò)程劃分為5個(gè)階段。

這些階段對(duì)于其他語(yǔ)言的學(xué)習(xí)也是成立的。理解自己處于哪個(gè)階段,可以幫助你找到提高自己的最有效的方法,也可以避免每個(gè)階段學(xué)習(xí)過(guò)程中的常見陷阱。

編者按:這篇文章對(duì)于每一個(gè)學(xué)習(xí)階段都給出了交互式的代碼片段。點(diǎn)擊函數(shù)名你就可以跳到具體的函數(shù)定義,方便進(jìn)行深入的研究。請(qǐng)看下文。

這里是GO程序員的五個(gè)進(jìn)化階段:

  • 第一個(gè)階段(菜逼) : 剛剛學(xué)習(xí)了這門語(yǔ)言。 已經(jīng)通過(guò)一些教程或者培訓(xùn)班了解基本的語(yǔ)法,可以寫短的代碼片段。

  • 第二個(gè)階段 (探索者) : 可以寫一個(gè)完整的程序,但不懂一些更高級(jí)的語(yǔ)言特征,比如“channels”。還沒(méi)有使用GO寫一個(gè)大項(xiàng)目。

  • 第三個(gè)階段(大手) : 你能熟練的使用Go, 能夠用GO去解決,生產(chǎn)環(huán)境中一個(gè)具體和完整的問(wèn)題。已經(jīng)形成了一套自己的慣用法和常用代碼庫(kù)。在你的編碼方案中Go是一個(gè)非常好用的工具。

  • 第四階段 (大神) : 絕逼清楚Go語(yǔ)言的設(shè)計(jì)選擇和背后的動(dòng)機(jī)。能理解的簡(jiǎn)潔和可組合性哲學(xué)。

  • 布道師 : 積極地與他人分享關(guān)于Go語(yǔ)言知識(shí)和你對(duì)Go語(yǔ)言的理解。在各種合適的場(chǎng)所發(fā)出自己的聲音, 參與郵件列表、建立QQ群、做專題報(bào)告。成為一個(gè)布道者不見得是一個(gè)完全獨(dú)立的階段,這個(gè)角色可以在上述的任何一個(gè)階段中。

第一階段: 菜逼

菜鳥在這個(gè)階段使用Go去創(chuàng)建一些小項(xiàng)目或者玩具項(xiàng)目。他們應(yīng)該會(huì)利用到 Go tour , Go playground , Go文檔 , 和郵件列表( golang-nuts ).

func main() {
  fmt.Println(stringutil.Reverse("!selpmaxe oG ,olleH"))}

查看上下文

func main in golang / example on Sourcegraph

這是Go語(yǔ)言寫的簡(jiǎn)單例子,這個(gè)代碼段來(lái)自 golang/example  代碼庫(kù)里面的 hello.go 。 點(diǎn)擊就可以查看完整代碼擼。

一項(xiàng)重要的技能,新人應(yīng)該試著學(xué)習(xí)如何正確提問(wèn)。很多新人在郵件列表里面這樣說(shuō)“嘿,這報(bào)錯(cuò)了”,這并沒(méi)有提供足夠的信息,讓別人能理解并幫助他們解決問(wèn)題。別人看到的是一個(gè)粘貼了幾百行的代碼的帖子,并沒(méi)有花費(fèi)精力來(lái)重點(diǎn)說(shuō)明所遇到的問(wèn)題。

所以, 應(yīng)該盡量避免直接粘貼代碼到論壇。而應(yīng)該使用可以編輯并且可以在瀏覽器中直接運(yùn)行的Go playground的“分享”按鈕鏈接到代碼片段。

Phase 2: the explorer

探索者已經(jīng)可以使用Go寫一些小的軟件,但有時(shí)仍然會(huì)有些迷茫。他們可能不完全明白怎么使用Go的高級(jí)特性,比如通道。雖然他們還有很多東西要學(xué)習(xí),但已掌握的足夠做一些有用的事情了!他們開始對(duì)Go的潛能有感覺(jué)了,并對(duì)它們能使用Go創(chuàng)建的東西感到興奮。

在探索階段通常會(huì)經(jīng)歷兩個(gè)步驟。第一,膨脹的預(yù)期達(dá)到頂點(diǎn),你覺(jué)得可以用Go做所有的事情,但還并不能明白或領(lǐng)悟到Go的真諦。你大概會(huì)用所熟悉的語(yǔ)言的模式和慣用語(yǔ)來(lái)寫Go代碼,但對(duì)于什么是地道的Go,還沒(méi)有比較強(qiáng)烈的感覺(jué)。你開始嘗試著手干這樣的事情--“遷移架構(gòu)X,從Y語(yǔ)言到Go語(yǔ)言”。

到達(dá)預(yù)期膨脹的頂點(diǎn)之后,你會(huì)遇到理想幻滅的低谷。你開始想念語(yǔ)言Y的特性X,此時(shí)你還沒(méi)有完全的掌握地道的Go。你還在用其他編程語(yǔ)言的風(fēng)格來(lái)寫Go語(yǔ)言的程序,你甚至開始覺(jué)得沮喪。你可能在大量使用reflect和unsafe這兩個(gè)包,但這不是地道的Go。地道的Go不會(huì)使用那些魔法一樣的東西。

這個(gè)探索階段產(chǎn)生的項(xiàng)目的一個(gè)很好的例子就是 Martini Web框架 。Martini是一個(gè)Go語(yǔ)言的早期Web框架,它從Ruby的Web框架當(dāng)中吸收了很多思想(比如依賴注入)。最初,這個(gè)框架在社區(qū)中引起了強(qiáng)烈的反響,但是它逐漸在性能和可調(diào)試性上受到了一些批評(píng)。Martini框架的作者Jeremy Saenz積極響應(yīng)這些來(lái)自Go社區(qū)的反饋,寫了一個(gè)更加符合Go語(yǔ)言規(guī)范的庫(kù) 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).RunOnAddr in  go-martini / martini on  Sourcegraph

來(lái)自Martini框架的交互式代碼片段,它是不地道的Go的例子。注意用反射包實(shí)現(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)}

查看上下文

func TestNegroniServeHTTP in  codegangsta / negroni on  * Sourcegraph

來(lái)自Negroni庫(kù)的交互式代碼片段,它是地道的Go的例子

其他語(yǔ)言在提供一些核心功能,比如HTTP處理的時(shí)候,往往需要依賴第三方庫(kù)。但是Go語(yǔ)言在這一點(diǎn)上很不同,它的標(biāo)準(zhǔn)庫(kù)非常強(qiáng)大。如果你認(rèn)為Go標(biāo)準(zhǔn)庫(kù)沒(méi)有強(qiáng)大到可以做你想做的事情,那么我說(shuō)你錯(cuò)了。Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)難以置信的強(qiáng)大,值得你花時(shí)間閱讀它的代碼,學(xué)習(xí)它實(shí)現(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)})}

在上下文中查看

(*Server).ListenAndServe in  golang / go on * Sourcegraph

Go標(biāo)準(zhǔn)庫(kù)中的ListenAndServe函數(shù)片段。如果你寫過(guò)Go程序,你可能已經(jīng)調(diào)用過(guò)這個(gè)函數(shù)很多次了,但是你曾經(jīng)花時(shí)間看過(guò)它的實(shí)現(xiàn)么?去點(diǎn)擊上面的代碼片段吧。

幻滅的低谷中的幻滅感來(lái)自于這樣的事實(shí):你還在用其他語(yǔ)言的模式來(lái)想問(wèn)題,而且你還沒(méi)有完全探索過(guò)Go能提供給你什么。下面是一些好玩的事情,你可以做一下來(lái)打破困境,進(jìn)一步探索這門語(yǔ)言中好玩的事。

go generate

現(xiàn)在來(lái)看看go generate。go generate是一個(gè)你可以用來(lái)自動(dòng)自成Go代碼的命令。你可以結(jié)合例如jsonenums(一個(gè)用于為枚舉類型自動(dòng)生成JSON編組樣板代碼的類庫(kù))這樣的元編程來(lái)使用go generate快速自動(dòng)實(shí)現(xiàn)重復(fù)乏味代碼的編寫。在Go標(biāo)準(zhǔn)類庫(kù)里面已經(jīng)有大量可以用于解析AST的接口,而AST使得編寫元編程工具更簡(jiǎn)單,更容易。在會(huì)議上,有另外兩次討論( Go語(yǔ)言中的元編程實(shí)踐擁抱標(biāo)準(zhǔn)類庫(kù) )談及到了這一點(diǎ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)
    }
  }}

查看上下文

Sourcegraph 站點(diǎn)上 campoy / jsonenums 中的  main 函數(shù)

一段互動(dòng)的片段演示了如何編寫 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()
  }}

在文本中查看

Sourcegraph 中  go-gl / examples 里面的函數(shù)  main

交互式的片段正說(shuō)明Go的OpenGL捆綁能制作Gopher cube。點(diǎn)擊函數(shù)或方法名去探索。

黑客馬拉松和挑戰(zhàn)

你也可以觀看挑戰(zhàn)和黑客馬拉松,類似 Gopher GalaGo Challenge 。在過(guò)去,來(lái)自世界各地的程序員一起挑戰(zhàn)一些真實(shí)的酷項(xiàng)目,你可以從中獲取靈感。

第三階段: 老手

作為一個(gè)老手,這意味著你可以解決很多Go語(yǔ)言中你關(guān)心的問(wèn)題。新的需要解決的問(wèn)題會(huì)帶來(lái)新的疑問(wèn),經(jīng)過(guò)試錯(cuò),你學(xué)會(huì)了在這門語(yǔ)言中什么是可以做的,什么是不能做的。此時(shí),你已經(jīng)對(duì)這門語(yǔ)言的習(xí)慣和模式有了一個(gè)堅(jiān)實(shí)的理解。你可以非常高效地工作,寫出可讀,文檔完善,可維護(hù)的代碼。

成為老手的一個(gè)很好的方法就是在大項(xiàng)目上工作。如果你自己有一個(gè)項(xiàng)目的想法,開始動(dòng)手去做吧(當(dāng)然你要確定它并不是已經(jīng)存在了)。大多數(shù)人也許并沒(méi)有一個(gè)很大的項(xiàng)目的想法,所以他們可以對(duì)已經(jīng)存在的項(xiàng)目做出貢獻(xiàn)。Go語(yǔ)言已經(jīng)有很多大型項(xiàng)目,而且它們正在被廣泛使用,比如Docker, Kubernetes和Go本身??梢钥纯催@個(gè) 項(xiàng)目列表

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}

在上下文中查看

(*DockerCli).CmdRestart   in   docker / docker   on  * Sourcegraph

Docker項(xiàng)目的交互式代碼片段。點(diǎn)擊函數(shù)名,開始探索之旅吧。

老手應(yīng)該對(duì)Go生態(tài)系統(tǒng)的工具有一個(gè)很強(qiáng)的掌握,因?yàn)檫@些工具真的提高生產(chǎn)效率。你應(yīng)該了解go generate,go vet,go test-race, 和gofmt/goimports/goreturns。你應(yīng)該使用go fmt,因?yàn)樗鼤?huì)自動(dòng)把你的代碼按照Go社區(qū)的風(fēng)格標(biāo)準(zhǔn)來(lái)格式化。goimports可以做同樣的事情,而且還會(huì)添加丟失的imports。goretures不光做了前面所說(shuō)的事情,還可以在返回表達(dá)式添加丟失的錯(cuò)誤,這是大家都討厭的地方。

在老手階段,你一定要開始做code review。code review的意義并不是要修改或者找到錯(cuò)誤(那是測(cè)試人員做的事情)。code review可以幫助維持統(tǒng)一的編程風(fēng)格,提高軟件的總體質(zhì)量,還可以在別人的反饋中提高你自己的編程技術(shù)。幾乎所有的大型開源項(xiàng)目都對(duì)每一個(gè)提交做code review。

下面是一個(gè)從人類的反饋當(dāng)中學(xué)習(xí)的例子:Google的Go團(tuán)隊(duì)以前都在main函數(shù)的外面聲明命令行標(biāo)記。在去年的GopherCon會(huì)議上,F(xiàn)rancesc遇到了SoundCloud公司的Peter Bourgon(@peterbourgon)。Peter Bourgon說(shuō)在SoundCloud,他們都在main函數(shù)內(nèi)部聲明標(biāo)記,這樣他們不會(huì)錯(cuò)誤地在外部使用標(biāo)記。Francesc現(xiàn)在認(rèn)為這是最佳實(shí)踐。

第四階段:專家

作為一個(gè)專家,你很好地了解了語(yǔ)言的哲學(xué)思想。對(duì)于Go語(yǔ)言的特性,你知道何時(shí)應(yīng)該使用,何時(shí)不應(yīng)該使用。例如,Jeremy Saenz在 dotGo風(fēng)暴討論 中談?wù)摰搅撕螘r(shí)不該使用接口。

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}

查看上下文

Sourcegraph 站點(diǎn)上 golang / go 中的   (*Client).Go

來(lái)自標(biāo)準(zhǔn)類庫(kù)的一小塊交互代碼片段使用了頻道。理解標(biāo)準(zhǔn)類庫(kù)里面的模式背后的決策原因是成為一個(gè)專家必經(jīng)之路。

但是不要成為只局限于單一語(yǔ)言的專家。跟其他任何語(yǔ)言一樣,Go僅僅只是一個(gè)工具。你還應(yīng)該去探索其他語(yǔ)言,并且學(xué)習(xí)他們的模式和風(fēng)格。Francesc從他使用Go的經(jīng)驗(yàn)中找到了編寫JavaScript的啟發(fā)。他還喜歡重點(diǎn)關(guān)注于不可變性和致力于避免易變性的Haskell語(yǔ)言,并從中獲得了如何編寫Go代碼的靈感。

布道者

作為一個(gè)布道者,你分享自己的知識(shí),傳授你學(xué)會(huì)的和你提出的最佳實(shí)踐。你可以分享自己對(duì)Go喜歡或者不喜歡的地方。全世界各地都有Go會(huì)議, 找到離你最近的

你可以在任何一個(gè)階段成為布道者,不要等到你成為這個(gè)領(lǐng)域的專家的時(shí)候才發(fā)出自己的聲音。在你學(xué)習(xí)Go的任何一個(gè)階段,提出問(wèn)題,結(jié)合你的經(jīng)驗(yàn)給出反饋,不要羞于提出自己不喜歡的地方。你提出的反饋可以幫助社區(qū)改善做事情的方法,也可能改變你自己對(duì)編程的看法。

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))

在上下文中查看

func main in golang / tools on Sourcegraph

流行的present命令的main函數(shù),很多Go的用戶使用它來(lái)制作幻燈片。許多演講者修改了這個(gè)模塊來(lái)滿足自己的需要。

Q&A

問(wèn):在GO語(yǔ)言中,我所懷念的一項(xiàng)功能是一個(gè)好的調(diào)試器。

答:我們正在做了,不只是調(diào)試器,我們還會(huì)提供一個(gè)更好的總體監(jiān)視工具可以讓你在程序運(yùn)行時(shí)更好地洞察程序在干什么(顯示出所有正在運(yùn)行的goroutine的狀態(tài))。在GO 1.5中探索它吧。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    久久精品少妇内射毛片| 空之色水之色在线播放| 亚洲第一视频少妇人妻系列 | 日韩精品在线观看完整版| 少妇人妻无一区二区三区| 久久香蕉综合网精品视频| 国产91麻豆精品成人区| 日韩一区二区三区久久| 日韩一区二区三区在线欧洲| 午夜国产精品国自产拍av| 激情五月综五月综合网| 少妇熟女精品一区二区三区| 欧美精品在线播放一区二区| 亚洲综合伊人五月天中文| 东京干男人都知道的天堂| 中文人妻精品一区二区三区四区| 亚洲国产成人爱av在线播放下载| 邻居人妻人公侵犯人妻视频| 欧美三级不卡在线观线看| 亚洲精品高清国产一线久久| 国产又大又黄又粗的黄色| 国产亚洲精品一二三区| 日韩中文字幕狠狠人妻| 蜜桃传媒在线正在播放| 精品日韩国产高清毛片| 草草夜色精品国产噜噜竹菊| 91久久精品中文内射| 亚洲国产欧美精品久久| 黄色污污在线免费观看| 不卡视频免费一区二区三区| 九九热最新视频免费观看| 在线观看免费无遮挡大尺度视频| 国产大屁股喷水在线观看视频| 年轻女房东2中文字幕| 国产免费自拍黄片免费看| 日韩人妻一区中文字幕| 在线九月婷婷丁香伊人| 亚洲最新中文字幕在线视频| 国产欧美日韩精品一区二| 不卡中文字幕在线免费看| 国产一区麻豆水好多高潮|